I am using react-select, in particular the Creatable component. My users are confused when they try to add a new item and they just type it in and then click somewhere else on the page. It doesn't actually create the item. I see that "enter" key or clicking the "add" link will add it but this is not intuitive for my users. Is there a way to force it to add the item when the user clicks away from the element?
I tried seeing if there were any props I could use to control this behavior.
I am using react-select, in particular the Creatable component. My users are confused when they try to add a new item and they just type it in and then click somewhere else on the page. It doesn't actually create the item. I see that "enter" key or clicking the "add" link will add it but this is not intuitive for my users. Is there a way to force it to add the item when the user clicks away from the element?
I tried seeing if there were any props I could use to control this behavior. https://react-select/props#creatable-props
Share Improve this question asked Jan 17 at 19:47 Josh WallaceJosh Wallace 31 bronze badge1 Answer
Reset to default 0Yes, you can pass a ref
to the CreatableSelect
component, and you can also attach an onBlur
event handler to it.
Let me explain each part in detail:
- Passing a
ref
toCreatableSelect
: TheCreatableSelect
component from thereact-select
library allows you to pass aref
if you need direct access to the DOM or component instance. This is useful if you want to trigger methods or access the component programmatically.
import React, { useState } from "react";
import CreatableSelect from "react-select/creatable";
const createOption = (label) => ({
label,
value: label.toLowerCase().replace(/\W/g, ""),
});
const defaultOptions = [
createOption("One"),
createOption("Two"),
createOption("Three"),
];
const SelectOptionList = () => {
const ref = React.useRef();
const [isLoading, setIsLoading] = useState(false);
const [options, setOptions] = useState(defaultOptions);
const [value, setValue] = useState();
const handleCreate = (inputValue) => {
setIsLoading(true);
setTimeout(() => {
const newOption = createOption(inputValue);
setIsLoading(false);
setOptions((prev) => [...prev, newOption]);
setValue(newOption);
}, 1000);
};
return (
<CreatableSelect
ref={ref}
isClearable
isDisabled={isLoading}
isLoading={isLoading}
onChange={(newValue) => setValue(newValue)}
onCreateOption={handleCreate}
options={options}
value={value}
/>
);
};
- Handling the
onBlur
event: TheonBlur
event inCreatableSelect
is triggered when the component loses focus, meaning when the user clicks outside of the select element. You can pass your ownonBlur
handler to run custom logic when this happens.
import React, { useState } from "react";
import CreatableSelect from "react-select/creatable";
const createOption = (label) => ({
label,
value: label.toLowerCase().replace(/\W/g, ""),
});
const defaultOptions = [
createOption("One"),
createOption("Two"),
createOption("Three"),
];
const SelectOptionList = () => {
const [isLoading, setIsLoading] = useState(false);
const [options, setOptions] = useState(defaultOptions);
const [value, setValue] = useState();
const handleCreate = (inputValue) => {
setIsLoading(true);
setTimeout(() => {
const newOption = createOption(inputValue);
setIsLoading(false);
setOptions((prev) => [...prev, newOption]);
setValue(newOption);
}, 1000);
};
const handleOnBlur = () => {
console.log('Blur triggered')
};
return (
<CreatableSelect
isClearable
isDisabled={isLoading}
isLoading={isLoading}
onChange={(newValue) => setValue(newValue)}
onCreateOption={handleCreate}
options={options}
value={value}
onBlur={handleOnBlur}
/>
);
};
Combining ref and onBlur
You can combine both ref
and onBlur
by passing both props to the CreatableSelect
component. The ref
allows you to manage focus or programmatically interact with the component, while onBlur
allows you to handle the loss of focus and execute your own logic.
Complete code:
import React, { useState } from "react";
import CreatableSelect from "react-select/creatable";
const createOption = (label) => ({
label,
value: label.toLowerCase().replace(/\W/g, ""),
});
const defaultOptions = [
createOption("One"),
createOption("Two"),
createOption("Three"),
];
const SelectOptionList = () => {
const ref = React.useRef();
const [isLoading, setIsLoading] = useState(false);
const [options, setOptions] = useState(defaultOptions);
const [value, setValue] = useState();
const handleCreate = (inputValue) => {
setIsLoading(true);
setTimeout(() => {
const newOption = createOption(inputValue);
setIsLoading(false);
setOptions((prev) => [...prev, newOption]);
setValue(newOption);
}, 1000);
};
const handleOnBlur = () => {
const inputValue = ref.current.props.inputValue;
if (inputValue) {
handleCreate(inputValue);
}
};
return (
<CreatableSelect
ref={ref}
isClearable
isDisabled={isLoading}
isLoading={isLoading}
onChange={(newValue) => setValue(newValue)}
onCreateOption={handleCreate}
options={options}
value={value}
onBlur={handleOnBlur}
/>
);
};
That's it. Let me know how it went :)