The React Select is a minimal select component for reactjs.
- React Select
- Installation
- Usage
- Examples
- Customization
- Dealing with extra content
- The render function
- Props
- Types
You can install the React Select component via npm:
npm i @oshq/react-select
import Select from '@oshq/react-select';
import '@oshq/react-select/index.css';
const App = () => {
const [selected, setSelected] = useState(undefined);
const options = [
{ label: 'apple', value: 'apple' },
{ label: 'ball', value: 'ball' },
{ label: 'cat', value: 'cat' },
{ label: 'dog', value: 'dog' },
];
return (
<Select
value={selected}
onChange={(_,val) => {
setSelected(val);
}}
options={async () => options}
/>
);
};
const App = () => {
const [selected, setSelected] = useState(undefined);
const options = [
{ label: "apple", value: "apple" },
{ label: "ball", value: "ball" },
{ label: "cat", value: "cat" },
{ label: "dog", value: "dog" },
];
return (
<Select
multiple
value={selected}
onChange={(_,val) => {
setSelected(val);
}}
options={async () => options}
/>
);
};
const App = () => {
const [selected, setSelected] = useState(undefined);
const options = [
{
label: "Fruits",
options: [
{ label: "Apple", value: "apple" },
{ label: "Mango", value: "mango" },
],
},
{
label: "Vegetables",
options: [
{ label: "Potato", value: "potato" },
{ label: "Pumpkin", value: "pumpkin" },
],
},
{
label: "Cereal",
options: [
{ label: "Maize", value: "maize" },
{ label: "rice", value: "rice" },
{ label: "Wheat", value: "wheat" },
],
},
];
return (
<Select
value={selected}
onChange={(_,val) => {
setSelected(val);
}}
options={async () => options}
/>
);
};
const App = () => {
const [selected, setSelected] = useState(undefined);
const options = [
{ label: 'apple', value: 'apple' },
{ label: 'ball', value: 'ball' },
{ label: 'cat', value: 'cat' },
{ label: 'dog', value: 'dog' },
];
return (
<Select
searchable
value={selected}
onChange={(_,val) => {
setSelected(val);
}}
options={async () => options}
/>
);
};
const App = () => {
const [selected, setSelected] = useState(undefined);
const options = [
{ label: "apple", value: "apple" },
{ label: "ball", value: "ball" },
{ label: "cat", value: "cat" },
{ label: "dog", value: "dog" },
];
return (
<Select
creatable
multiple
value={selected}
onChange={(_,val) => {
setSelected(val);
}}
options={async () => options}
/>
);
};
const App = () => {
const [selected, setSelected] = useState(undefined);
const options = async () => {
const data = await (
await fetch("fetch_api")
).json();
return [...data.map((res) => ({ label: res.title, value: res.id }))];
};
return (
<Select
searchable
value={selected}
onChange={(_,val) => {
setSelected(val);
}}
options={options}
/>
);
};
const App = () => {
const [selected, setSelected] = useState([]);
const options = [
{ label: "apple", value: "apple" },
{ label: "ball", value: "ball" },
{ label: "cat", value: "cat" },
{ label: "dog", value: "dog" },
];
const closeIcon = () => {
return (
<svg
width="12"
height="12"
strokeWidth="2"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 32 32"
>
<path
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
d="M24 8 8 24M24 24 8 8"
/>
</svg>
);
};
const chevronDown = () => {
return (
<svg
width="12"
height="12"
strokeWidth="2"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 32 32"
>
<path
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
d="M26 11 16 21 6 11"
/>
</svg>
);
};
return (
<Select
showclear
multiple
value={selected}
onChange={(_,val) => {
setSelected(val);
}}
options={async ()=> options}
placeholder={<div className="text-white/50">Customize</div>}
className={() => {
const custom =
"bg-black text-sm text-white px-2 py-0.5 border-solid font-sans border rounded min-w-[50px] outline-none";
return {
default: `${custom} border-stone-200`,
focus: `${custom} border-stone-200 ring-1 ring-orange-400`,
disabled: `${custom} text-black/25 bg-black/5 border-stone-100`,
};
}}
suffixRender={({ clear, showclear }) => {
return (
<div className="flex flex-row items-center gap-1 px-2">
{showclear && selected && selected?.length > 0 && (
<span className="cursor-pointer hover:opacity-60" onClick={clear}>
{closeIcon()}
</span>
)}
<span>{chevronDown()}</span>
</div>
);
}}
tagRender={({ label, remove, value }) => {
return (
<div className="bg-yellow-600 rounded px-1.5 truncate py-0.5 flex flex-row items-center justify-center gap-2">
<span className="truncate">{label}</span>
<span
className="cursor-pointer hover:opacity-60"
onClick={() => remove(value)}
>
{closeIcon()}
</span>
</div>
);
}}
menuClass="bg-yellow-600 p-1 rounded shadow-2xl"
menuItemRender={({ label, innerProps, active, focused }) => {
return (
<div className="py-px truncate" {...innerProps}>
<div
className={cn("py-2 px-1 rounded truncate", {
"bg-yellow-500": !!active,
"bg-yellow-400": !!focused && !active,
})}
>
{label}
</div>
</div>
);
}}
/>
);
};
If you're handling additional data, React Select seamlessly supports it out of the box. Simply include your data alongside { label, value, ....your_extra_data_here }
for each item. For instance, consider the following example where country
is included as extra data. This supplementary information can also be accessed upon triggering the onChange
event.
const countries = async () => {
const data = await (
await fetch(
'https://cdn.jsdelivr.net/npm/country-flag-emoji-json@2.0.0/dist/index.json'
)
).json();
return [
...data.map((country) => ({
label: `${country.name}`,
value: `${country.code}`,
render: () => (
<div className="flex flex-row items-center gap-1 truncate">
<span>{country.emoji}</span>
<span className="truncate">{country.name}</span>
</div>
),
country,
})),
];
};
const App = () => {
const [selected, setSelected] = useState(undefined);
return (
<Select
value={selected}
onChange={(_,val) => {
setSelected(val);
}}
options={countries}
valueRender={(value) => (
<div className="flex flex-row items-center gap-1">
<span>{value.country.emoji}</span>
<span>{value.label}</span>
</div>
)}
/>
);
};
You have the option to include a render function alongside your items. Take this JSX snippet, for instance:
{
label: "Hello world",
value: "hello",
render: ({ active, focused }) => <div>Hello world</div>,
}
This feature empowers you to tailor each option item according to your preferences.
-
Type:
async () => [....]
- Description: Asynchronously retrieves selectable options for the Select component. Expects a function returning a Promise resolving to an array of objects representing options or a complex structure for grouped options, including labels and values.
-
Type:
string | string[]
- Description: Represents the current value(s) of the Select component. It should be string or array of string.
-
Type:
ReactNode
- Description: Customizable message or ReactNode to display when no options are available within the Select component.
-
Type:
boolean
-
Default:
false
- Description: Disables the Select component while asynchronously fetching options to prevent interaction until options are loaded.
-
Type:
ReactNode
- Description: Placeholder text or ReactNode displayed when no option is selected.
-
Type:
boolean
-
Default:
false
- Description: Determines whether the Select component allows multiple options to be selected.
-
Type:
boolean | undefined
-
Default:
false
- Description: Controls the visibility of the dropdown menu.
-
Type:
boolean
-
Default:
false
-
Description: Disables the Select component when set to
true
.
-
Type:
boolean
-
Default:
true
- Description: Enables a search feature within the Select component to quickly find options.
-
Type:
boolean
-
Default:
false
- Description: Enables users to create new options within the Select component.
-
Type:
boolean
-
Default:
false
- Description: Displays a clear button for removing selected value(s).
-
Type:
(value: ISuffixRender) => ReactNode
- Description: Allows customizing the appearance of the suffix area in the Select component.
-
Type:
(value: IGroupRender) => ReactNode
- Description: Enables custom rendering styles for group label.
-
Type:
(value: ITagRender) => ReactNode
- Description: Customizes the rendering style for selected tags, in multi-selection scenarios.
-
Type:
(value: IMenuItemRender) => ReactNode
- Description: Facilitates customization of individual menu item's renderings.
-
Type:
(value: type_of_item) => ReactNode
- Description: Customizes the rendering style for selected value in input field.
-
Type:
string | (() => { focus?: string; disabled?: string; default?: string })
- Description: CSS classes for customizing select input field.
-
Type:
string
- Description: CSS classes for the portal element.
-
Type:
string
- Description: CSS classes for the dropdown menu container of the Select component.
-
Type:
null | AnimationProps(FramerMotion animation props)
- Description: Configures animations for the dropdown menu. When set null, disables the animation.
-
Type:
(value:object, valueAsString:string) => void
- Description: Triggered upon changes to the selected value(s).
-
Type:
(open: boolean) => void
- Description: Triggered when the dropdown menu opens or closes.
-
Type:
(text: string) => void | boolean
- Description: Triggers when typing. If true or void is returned then it uses in-build filtering.
-
Type:
string
-
Default:
Create
- Description: Prefix label for creating new element.
-
Type:
boolean
-
Default:
false
- Description: Hides select popup menu.
type ISuffixRender = {
showclear?: boolean | undefined;
clear?: (() => void) | undefined;
isOpen?: boolean | undefined;
loading?: boolean | undefined;
}
type IGroupRender = {
label: string;
}
type ITagRender = {
remove: (value: string) => void;
value: string;
label: string;
}
type IOptionRender = ({
active,
focused,
disabled,
groupMode,
}: {
active: boolean;
focused: boolean;
disabled?: boolean;
groupMode?: boolean;
}) => ReactNode;
type IMenuItemRender = {
active?: boolean | undefined;
focused?: boolean | undefined;
label: string;
value: string;
render: IOptionRender;
innerProps?: { ... } | undefined;
}