React AriaExamples

User Search ComboBox

A user search ComboBox styled with Tailwind CSS.

Example#


import {Button, ComboBox, Group, Input, Label, ListBox, ListBoxItem, Popover} from 'react-aria-components';
import type {ListBoxItemProps} from 'react-aria-components';
import ChevronUpDownIcon from '@spectrum-icons/workflow/ChevronUpDown';
import CheckIcon from '@spectrum-icons/workflow/Checkmark';

function ComboBoxExample() {
  return (
    <div className="bg-gradient-to-r from-sky-300 to-cyan-300 p-8 sm:h-[300px] rounded-lg flex justify-center">
      <ComboBox className="group flex flex-col gap-1 w-[200px]">
        <Label className="text-black cursor-default">Assignee</Label>
        <Group className="flex rounded-lg bg-white bg-opacity-90 focus-within:bg-opacity-100 transition shadow-md ring-1 ring-black/10 focus-visible:ring-2 focus-visible:ring-black">
          <Input className="flex-1 w-full border-none py-2 px-3 leading-5 text-gray-900 bg-transparent outline-none text-base" />
          <Button className="px-3 flex items-center text-gray-700 transition border-0 border-solid border-l border-l-sky-200 bg-transparent rounded-r-lg pressed:bg-sky-100">
            <ChevronUpDownIcon size="XS" />
          </Button>
        </Group>
        <Popover className="max-h-60 w-[--trigger-width] overflow-auto 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">
          <ListBox className="outline-none p-1" items={people}>
            {(item) => (
              <UserItem textValue={item.name}>
                <img
                  alt=""
                  src={item.avatar}
                  className="w-6 h-6 rounded-full"
                />
                <span className="truncate">{item.name}</span>
              </UserItem>
            )}
          </ListBox>
        </Popover>
      </ComboBox>
    </div>
  );
}

function UserItem(props: ListBoxItemProps & { children: React.ReactNode }) {
  return (
    <ListBoxItem
      {...props}
      className="group flex items-center gap-2 cursor-default select-none py-2 pl-2 pr-4 outline-none rounded text-gray-900 focus:bg-sky-600 focus:text-white"
    >
      {({ isSelected }) => (
        <>
          <span className="flex-1 flex items-center gap-3 truncate font-normal group-selected:font-medium">
            {props.children}
          </span>
          {isSelected &&
            (
              <span className="w-5 flex items-center text-sky-600 group-focus:text-white">
                <CheckIcon size="S" />
              </span>
            )}
        </>
      )}
    </ListBoxItem>
  );
}
import {
  Button,
  ComboBox,
  Group,
  Input,
  Label,
  ListBox,
  ListBoxItem,
  Popover
} from 'react-aria-components';
import type {ListBoxItemProps} from 'react-aria-components';
import ChevronUpDownIcon from '@spectrum-icons/workflow/ChevronUpDown';
import CheckIcon from '@spectrum-icons/workflow/Checkmark';

function ComboBoxExample() {
  return (
    <div className="bg-gradient-to-r from-sky-300 to-cyan-300 p-8 sm:h-[300px] rounded-lg flex justify-center">
      <ComboBox className="group flex flex-col gap-1 w-[200px]">
        <Label className="text-black cursor-default">
          Assignee
        </Label>
        <Group className="flex rounded-lg bg-white bg-opacity-90 focus-within:bg-opacity-100 transition shadow-md ring-1 ring-black/10 focus-visible:ring-2 focus-visible:ring-black">
          <Input className="flex-1 w-full border-none py-2 px-3 leading-5 text-gray-900 bg-transparent outline-none text-base" />
          <Button className="px-3 flex items-center text-gray-700 transition border-0 border-solid border-l border-l-sky-200 bg-transparent rounded-r-lg pressed:bg-sky-100">
            <ChevronUpDownIcon size="XS" />
          </Button>
        </Group>
        <Popover className="max-h-60 w-[--trigger-width] overflow-auto 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">
          <ListBox
            className="outline-none p-1"
            items={people}
          >
            {(item) => (
              <UserItem textValue={item.name}>
                <img
                  alt=""
                  src={item.avatar}
                  className="w-6 h-6 rounded-full"
                />
                <span className="truncate">
                  {item.name}
                </span>
              </UserItem>
            )}
          </ListBox>
        </Popover>
      </ComboBox>
    </div>
  );
}

function UserItem(
  props: ListBoxItemProps & { children: React.ReactNode }
) {
  return (
    <ListBoxItem
      {...props}
      className="group flex items-center gap-2 cursor-default select-none py-2 pl-2 pr-4 outline-none rounded text-gray-900 focus:bg-sky-600 focus:text-white"
    >
      {({ isSelected }) => (
        <>
          <span className="flex-1 flex items-center gap-3 truncate font-normal group-selected:font-medium">
            {props.children}
          </span>
          {isSelected &&
            (
              <span className="w-5 flex items-center text-sky-600 group-focus:text-white">
                <CheckIcon size="S" />
              </span>
            )}
        </>
      )}
    </ListBoxItem>
  );
}
import {
  Button,
  ComboBox,
  Group,
  Input,
  Label,
  ListBox,
  ListBoxItem,
  Popover
} from 'react-aria-components';
import type {ListBoxItemProps} from 'react-aria-components';
import ChevronUpDownIcon from '@spectrum-icons/workflow/ChevronUpDown';
import CheckIcon from '@spectrum-icons/workflow/Checkmark';

function ComboBoxExample() {
  return (
    <div className="bg-gradient-to-r from-sky-300 to-cyan-300 p-8 sm:h-[300px] rounded-lg flex justify-center">
      <ComboBox className="group flex flex-col gap-1 w-[200px]">
        <Label className="text-black cursor-default">
          Assignee
        </Label>
        <Group className="flex rounded-lg bg-white bg-opacity-90 focus-within:bg-opacity-100 transition shadow-md ring-1 ring-black/10 focus-visible:ring-2 focus-visible:ring-black">
          <Input className="flex-1 w-full border-none py-2 px-3 leading-5 text-gray-900 bg-transparent outline-none text-base" />
          <Button className="px-3 flex items-center text-gray-700 transition border-0 border-solid border-l border-l-sky-200 bg-transparent rounded-r-lg pressed:bg-sky-100">
            <ChevronUpDownIcon size="XS" />
          </Button>
        </Group>
        <Popover className="max-h-60 w-[--trigger-width] overflow-auto 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">
          <ListBox
            className="outline-none p-1"
            items={people}
          >
            {(item) => (
              <UserItem
                textValue={item
                  .name}
              >
                <img
                  alt=""
                  src={item
                    .avatar}
                  className="w-6 h-6 rounded-full"
                />
                <span className="truncate">
                  {item
                    .name}
                </span>
              </UserItem>
            )}
          </ListBox>
        </Popover>
      </ComboBox>
    </div>
  );
}

function UserItem(
  props:
    & ListBoxItemProps
    & {
      children:
        React.ReactNode;
    }
) {
  return (
    <ListBoxItem
      {...props}
      className="group flex items-center gap-2 cursor-default select-none py-2 pl-2 pr-4 outline-none rounded text-gray-900 focus:bg-sky-600 focus:text-white"
    >
      {(
        { isSelected }
      ) => (
        <>
          <span className="flex-1 flex items-center gap-3 truncate font-normal group-selected:font-medium">
            {props
              .children}
          </span>
          {isSelected &&
            (
              <span className="w-5 flex items-center text-sky-600 group-focus:text-white">
                <CheckIcon size="S" />
              </span>
            )}
        </>
      )}
    </ListBoxItem>
  );
}

Tailwind config#

This example uses the following plugins:

Add them to your tailwind.config.js:

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'
    )
  ]
};

Components#


ComboBox
A combobox combines a text input with a listbox, and allows a user to filter a list of options.
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.