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 :)