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.com/props#creatable-props
Yes, 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:
ref to CreatableSelect: The CreatableSelect component from the react-select library allows you to pass a ref 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}
/>
);
};
onBlur event: The onBlur event in CreatableSelect is triggered when the component loses focus, meaning when the user clicks outside of the select element. You can pass your own onBlur 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 :)
