Searchable Select
A Select component with Autocomplete filtering.
Example#
import type {ListBoxItemProps} from 'react-aria-components'; import {Autocomplete, Button, Input, Label, ListBox, ListBoxItem, Popover, SearchField, Select, SelectValue, useFilter} from 'react-aria-components'; import {CheckIcon, CheckIcon, ChevronsUpDownIcon, SearchIcon, XIcon} from 'lucide-react'; function SelectExample() { let { contains } = useFilter({ sensitivity: 'base' }); return ( <div className="bg-linear-to-br from-cyan-200 to-blue-400 p-8 sm:h-[350px] rounded-lg flex justify-center"> <Select className="flex flex-col gap-1 w-[200px] relative"> <Label className="text-black cursor-default">Language</Label> <Button className="flex items-center cursor-default rounded-lg border-0 bg-white/90 pressed:bg-white transition py-2 pl-5 pr-2 text-base text-left leading-normal ring-1 ring-black/5 shadow-md text-gray-700 focus:outline-hidden focus-visible:outline-2 outline-black outline-offset-3 focus-visible:ring-black/25"> <SelectValue className="flex-1 truncate" /> <ChevronsUpDownIcon className="w-4 h-4" /> </Button> <Popover className="!max-h-80 w-(--trigger-width) flex flex-col rounded-md bg-white text-base shadow-lg ring-1 ring-black/5 entering:animate-in entering:fade-in exiting:animate-out exiting:fade-out"> <Autocomplete filter={contains}> <SearchField aria-label="Search" autoFocus className="group flex items-center bg-white forced-colors:bg-[Field] border-2 border-gray-300 has-focus:border-sky-600 rounded-full m-1" > <SearchIcon aria-hidden className="w-4 h-4 ml-2 text-gray-600 forced-colors:text-[ButtonText]" /> <Input placeholder="Search languages" className="px-2 py-1 flex-1 min-w-0 border-none outline outline-0 bg-white text-base text-gray-800 placeholder-gray-500 font-[inherit] [&::-webkit-search-cancel-button]:hidden" /> <Button className="text-sm text-center transition rounded-full border-0 p-1 flex items-center justify-center text-gray-600 bg-transparent hover:bg-black/[5%] pressed:bg-black/10 mr-1 w-6 group-empty:invisible"> <XIcon aria-hidden className="w-4 h-4" /> </Button> </SearchField> <ListBox items={languages} className="outline-hidden p-1 overflow-auto flex-1 scroll-pb-1" > {(item) => <SelectItem>{item.name}</SelectItem>} </ListBox> </Autocomplete> </Popover> </Select> </div> ); } function SelectItem(props: ListBoxItemProps & { children: string }) { return ( <ListBoxItem {...props} textValue={props.children} className="group flex items-center gap-2 cursor-default select-none py-2 px-4 outline-hidden rounded-sm text-gray-900 focus:bg-sky-600 focus:text-white" > {({ isSelected }) => ( <> <span className="flex-1 flex items-center gap-2 truncate font-normal group-selected:font-medium"> {props.children} </span> <span className="w-5 flex items-center text-sky-600 group-focus:text-white"> {isSelected && <CheckIcon size="S" />} </span> </> )} </ListBoxItem> ); }
import type {ListBoxItemProps} from 'react-aria-components'; import { Autocomplete, Button, Input, Label, ListBox, ListBoxItem, Popover, SearchField, Select, SelectValue, useFilter } from 'react-aria-components'; import { CheckIcon, CheckIcon, ChevronsUpDownIcon, SearchIcon, XIcon } from 'lucide-react'; function SelectExample() { let { contains } = useFilter({ sensitivity: 'base' }); return ( <div className="bg-linear-to-br from-cyan-200 to-blue-400 p-8 sm:h-[350px] rounded-lg flex justify-center"> <Select className="flex flex-col gap-1 w-[200px] relative"> <Label className="text-black cursor-default"> Language </Label> <Button className="flex items-center cursor-default rounded-lg border-0 bg-white/90 pressed:bg-white transition py-2 pl-5 pr-2 text-base text-left leading-normal ring-1 ring-black/5 shadow-md text-gray-700 focus:outline-hidden focus-visible:outline-2 outline-black outline-offset-3 focus-visible:ring-black/25"> <SelectValue className="flex-1 truncate" /> <ChevronsUpDownIcon className="w-4 h-4" /> </Button> <Popover className="!max-h-80 w-(--trigger-width) flex flex-col rounded-md bg-white text-base shadow-lg ring-1 ring-black/5 entering:animate-in entering:fade-in exiting:animate-out exiting:fade-out"> <Autocomplete filter={contains}> <SearchField aria-label="Search" autoFocus className="group flex items-center bg-white forced-colors:bg-[Field] border-2 border-gray-300 has-focus:border-sky-600 rounded-full m-1" > <SearchIcon aria-hidden className="w-4 h-4 ml-2 text-gray-600 forced-colors:text-[ButtonText]" /> <Input placeholder="Search languages" className="px-2 py-1 flex-1 min-w-0 border-none outline outline-0 bg-white text-base text-gray-800 placeholder-gray-500 font-[inherit] [&::-webkit-search-cancel-button]:hidden" /> <Button className="text-sm text-center transition rounded-full border-0 p-1 flex items-center justify-center text-gray-600 bg-transparent hover:bg-black/[5%] pressed:bg-black/10 mr-1 w-6 group-empty:invisible"> <XIcon aria-hidden className="w-4 h-4" /> </Button> </SearchField> <ListBox items={languages} className="outline-hidden p-1 overflow-auto flex-1 scroll-pb-1" > {(item) => ( <SelectItem>{item.name}</SelectItem> )} </ListBox> </Autocomplete> </Popover> </Select> </div> ); } function SelectItem( props: ListBoxItemProps & { children: string } ) { return ( <ListBoxItem {...props} textValue={props.children} className="group flex items-center gap-2 cursor-default select-none py-2 px-4 outline-hidden rounded-sm text-gray-900 focus:bg-sky-600 focus:text-white" > {({ isSelected }) => ( <> <span className="flex-1 flex items-center gap-2 truncate font-normal group-selected:font-medium"> {props.children} </span> <span className="w-5 flex items-center text-sky-600 group-focus:text-white"> {isSelected && <CheckIcon size="S" />} </span> </> )} </ListBoxItem> ); }
import type {ListBoxItemProps} from 'react-aria-components'; import { Autocomplete, Button, Input, Label, ListBox, ListBoxItem, Popover, SearchField, Select, SelectValue, useFilter } from 'react-aria-components'; import { CheckIcon, CheckIcon, ChevronsUpDownIcon, SearchIcon, XIcon } from 'lucide-react'; function SelectExample() { let { contains } = useFilter({ sensitivity: 'base' }); return ( <div className="bg-linear-to-br from-cyan-200 to-blue-400 p-8 sm:h-[350px] rounded-lg flex justify-center"> <Select className="flex flex-col gap-1 w-[200px] relative"> <Label className="text-black cursor-default"> Language </Label> <Button className="flex items-center cursor-default rounded-lg border-0 bg-white/90 pressed:bg-white transition py-2 pl-5 pr-2 text-base text-left leading-normal ring-1 ring-black/5 shadow-md text-gray-700 focus:outline-hidden focus-visible:outline-2 outline-black outline-offset-3 focus-visible:ring-black/25"> <SelectValue className="flex-1 truncate" /> <ChevronsUpDownIcon className="w-4 h-4" /> </Button> <Popover className="!max-h-80 w-(--trigger-width) flex flex-col rounded-md bg-white text-base shadow-lg ring-1 ring-black/5 entering:animate-in entering:fade-in exiting:animate-out exiting:fade-out"> <Autocomplete filter={contains} > <SearchField aria-label="Search" autoFocus className="group flex items-center bg-white forced-colors:bg-[Field] border-2 border-gray-300 has-focus:border-sky-600 rounded-full m-1" > <SearchIcon aria-hidden className="w-4 h-4 ml-2 text-gray-600 forced-colors:text-[ButtonText]" /> <Input placeholder="Search languages" className="px-2 py-1 flex-1 min-w-0 border-none outline outline-0 bg-white text-base text-gray-800 placeholder-gray-500 font-[inherit] [&::-webkit-search-cancel-button]:hidden" /> <Button className="text-sm text-center transition rounded-full border-0 p-1 flex items-center justify-center text-gray-600 bg-transparent hover:bg-black/[5%] pressed:bg-black/10 mr-1 w-6 group-empty:invisible"> <XIcon aria-hidden className="w-4 h-4" /> </Button> </SearchField> <ListBox items={languages} className="outline-hidden p-1 overflow-auto flex-1 scroll-pb-1" > {(item) => ( <SelectItem> {item .name} </SelectItem> )} </ListBox> </Autocomplete> </Popover> </Select> </div> ); } function SelectItem( props: & ListBoxItemProps & { children: string; } ) { return ( <ListBoxItem {...props} textValue={props .children} className="group flex items-center gap-2 cursor-default select-none py-2 px-4 outline-hidden rounded-sm text-gray-900 focus:bg-sky-600 focus:text-white" > {( { isSelected } ) => ( <> <span className="flex-1 flex items-center gap-2 truncate font-normal group-selected:font-medium"> {props .children} </span> <span className="w-5 flex items-center text-sky-600 group-focus:text-white"> {isSelected && ( <CheckIcon size="S" /> )} </span> </> )} </ListBoxItem> ); }
Tailwind config#
This example uses the following plugins:
When using Tailwind v4, add them to your CSS:
@import "tailwindcss"; @plugin "tailwindcss-react-aria-components"; @plugin "tailwindcss-animate";
@import "tailwindcss"; @plugin "tailwindcss-react-aria-components"; @plugin "tailwindcss-animate";
@import "tailwindcss"; @plugin "tailwindcss-react-aria-components"; @plugin "tailwindcss-animate";
Tailwind v3
When using Tailwind v3, add the plugins to your tailwind.config.js
instead:
module.exports = { // ... plugins: [ require('tailwindcss-react-aria-components'), require('tailwindcss-animate') ] };
module.exports = { // ... plugins: [ require('tailwindcss-react-aria-components'), require('tailwindcss-animate') ] };
module.exports = { // ... plugins: [ require( 'tailwindcss-react-aria-components' ), require( 'tailwindcss-animate' ) ] };
Note: When using Tailwind v3, install tailwindcss-react-aria-components
version 1.x instead of 2.x.
Components#
Select
A select displays a collapsible list of options, and allows a user to select one of them.
ListBox
A listbox allows a user to select one or more options from a list.
Popover
A popover displays content in context with a trigger element.
Button
A button allows a user to perform an action.
SearchField
A search field allows a user to enter and clear a search query.