React AriaExamples

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]">
        <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]">
        <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]">
        <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.