SelectPreview

A select displays a collapsible list of options and allows a user to select one of them

Import

import { Select } from '@heroui/react';

Usage

State
import {Label, ListBox, Select} from "@heroui/react";

export function Default() {
  return (
    <Select className="w-[256px]" placeholder="Select one">
      <Label>State</Label>
      <Select.Trigger>
        <Select.Value />
        <Select.Indicator />
      </Select.Trigger>
      <Select.Content>
        <ListBox>
          <ListBox.Item id="florida" textValue="Florida">
            Florida
            <ListBox.ItemIndicator />
          </ListBox.Item>
          <ListBox.Item id="delaware" textValue="Delaware">
            Delaware
            <ListBox.ItemIndicator />
          </ListBox.Item>
          <ListBox.Item id="california" textValue="California">
            California
            <ListBox.ItemIndicator />
          </ListBox.Item>
          <ListBox.Item id="texas" textValue="Texas">
            Texas
            <ListBox.ItemIndicator />
          </ListBox.Item>
          <ListBox.Item id="new-york" textValue="New York">
            New York
            <ListBox.ItemIndicator />
          </ListBox.Item>
          <ListBox.Item id="washington" textValue="Washington">
            Washington
            <ListBox.ItemIndicator />
          </ListBox.Item>
        </ListBox>
      </Select.Content>
    </Select>
  );
}

Anatomy

Import the Select component and access all parts using dot notation.

import { Select, Label, Description, Header, ListBox, Separator } from '@heroui/react';

export default () => (
  <Select>
    <Label />
    <Select.Trigger>
      <Select.Value />
      <Select.Indicator />
    </Select.Trigger>
    <Description />
    <Select.Content>
      <ListBox>
        <ListBox.Item>
          <Label />
          <Description />
          <ListBox.ItemIndicator />
        </ListBox.Item>
        <ListBox.Section>
          <Header />
          <ListBox.Item>
            <Label />
          </ListBox.Item>
        </ListBox.Section>
      </ListBox>
    </Select.Content>
  </Select>
)

With Description

StateSelect your state of residence
import {Description, Label, ListBox, Select} from "@heroui/react";

export function WithDescription() {
  return (
    <Select className="w-[256px]" placeholder="Select one">
      <Label>State</Label>
      <Select.Trigger>
        <Select.Value />
        <Select.Indicator />
      </Select.Trigger>
      <Select.Content>
        <ListBox>
          <ListBox.Item id="florida" textValue="Florida">
            Florida
            <ListBox.ItemIndicator />
          </ListBox.Item>
          <ListBox.Item id="delaware" textValue="Delaware">
            Delaware
            <ListBox.ItemIndicator />
          </ListBox.Item>
          <ListBox.Item id="california" textValue="California">
            California
            <ListBox.ItemIndicator />
          </ListBox.Item>
          <ListBox.Item id="texas" textValue="Texas">
            Texas
            <ListBox.ItemIndicator />
          </ListBox.Item>
          <ListBox.Item id="new-york" textValue="New York">
            New York
            <ListBox.ItemIndicator />
          </ListBox.Item>
          <ListBox.Item id="washington" textValue="Washington">
            Washington
            <ListBox.ItemIndicator />
          </ListBox.Item>
        </ListBox>
      </Select.Content>
      <Description>Select your state of residence</Description>
    </Select>
  );
}

Multiple Select

Countries to Visit
import {Label, ListBox, Select} from "@heroui/react";

export function MultipleSelect() {
  return (
    <Select className="w-[256px]" placeholder="Select countries" selectionMode="multiple">
      <Label>Countries to Visit</Label>
      <Select.Trigger>
        <Select.Value />
        <Select.Indicator />
      </Select.Trigger>
      <Select.Content>
        <ListBox selectionMode="multiple">
          <ListBox.Item id="argentina" textValue="Argentina">
            Argentina
            <ListBox.ItemIndicator />
          </ListBox.Item>
          <ListBox.Item id="venezuela" textValue="Venezuela">
            Venezuela
            <ListBox.ItemIndicator />
          </ListBox.Item>
          <ListBox.Item id="japan" textValue="Japan">
            Japan
            <ListBox.ItemIndicator />
          </ListBox.Item>
          <ListBox.Item id="france" textValue="France">
            France
            <ListBox.ItemIndicator />
          </ListBox.Item>
          <ListBox.Item id="italy" textValue="Italy">
            Italy
            <ListBox.ItemIndicator />
          </ListBox.Item>
          <ListBox.Item id="spain" textValue="Spain">
            Spain
            <ListBox.ItemIndicator />
          </ListBox.Item>
          <ListBox.Item id="thailand" textValue="Thailand">
            Thailand
            <ListBox.ItemIndicator />
          </ListBox.Item>
          <ListBox.Item id="new-zealand" textValue="New Zealand">
            New Zealand
            <ListBox.ItemIndicator />
          </ListBox.Item>
          <ListBox.Item id="iceland" textValue="Iceland">
            Iceland
            <ListBox.ItemIndicator />
          </ListBox.Item>
        </ListBox>
      </Select.Content>
    </Select>
  );
}

With Sections

Country
import {Header, Label, ListBox, Select, Separator} from "@heroui/react";

export function WithSections() {
  return (
    <Select className="w-[256px]" placeholder="Select a country">
      <Label>Country</Label>
      <Select.Trigger>
        <Select.Value />
        <Select.Indicator />
      </Select.Trigger>
      <Select.Content>
        <ListBox>
          <ListBox.Section>
            <Header>North America</Header>
            <ListBox.Item id="usa" textValue="United States">
              United States
              <ListBox.ItemIndicator />
            </ListBox.Item>
            <ListBox.Item id="canada" textValue="Canada">
              Canada
              <ListBox.ItemIndicator />
            </ListBox.Item>
            <ListBox.Item id="mexico" textValue="Mexico">
              Mexico
              <ListBox.ItemIndicator />
            </ListBox.Item>
          </ListBox.Section>
          <Separator />
          <ListBox.Section>
            <Header>Europe</Header>
            <ListBox.Item id="uk" textValue="United Kingdom">
              United Kingdom
              <ListBox.ItemIndicator />
            </ListBox.Item>
            <ListBox.Item id="france" textValue="France">
              France
              <ListBox.ItemIndicator />
            </ListBox.Item>
            <ListBox.Item id="germany" textValue="Germany">
              Germany
              <ListBox.ItemIndicator />
            </ListBox.Item>
            <ListBox.Item id="spain" textValue="Spain">
              Spain
              <ListBox.ItemIndicator />
            </ListBox.Item>
            <ListBox.Item id="italy" textValue="Italy">
              Italy
              <ListBox.ItemIndicator />
            </ListBox.Item>
          </ListBox.Section>
          <Separator />
          <ListBox.Section>
            <Header>Asia</Header>
            <ListBox.Item id="japan" textValue="Japan">
              Japan
              <ListBox.ItemIndicator />
            </ListBox.Item>
            <ListBox.Item id="china" textValue="China">
              China
              <ListBox.ItemIndicator />
            </ListBox.Item>
            <ListBox.Item id="india" textValue="India">
              India
              <ListBox.ItemIndicator />
            </ListBox.Item>
            <ListBox.Item id="south-korea" textValue="South Korea">
              South Korea
              <ListBox.ItemIndicator />
            </ListBox.Item>
          </ListBox.Section>
        </ListBox>
      </Select.Content>
    </Select>
  );
}

With Disabled Options

Animal
import {Label, ListBox, Select} from "@heroui/react";

export function WithDisabledOptions() {
  return (
    <Select className="w-[256px]" disabledKeys={["cat", "kangaroo"]} placeholder="Select an animal">
      <Label>Animal</Label>
      <Select.Trigger>
        <Select.Value />
        <Select.Indicator />
      </Select.Trigger>
      <Select.Content>
        <ListBox>
          <ListBox.Item id="dog" textValue="Dog">
            Dog
            <ListBox.ItemIndicator />
          </ListBox.Item>
          <ListBox.Item id="cat" textValue="Cat">
            Cat
            <ListBox.ItemIndicator />
          </ListBox.Item>
          <ListBox.Item id="bird" textValue="Bird">
            Bird
            <ListBox.ItemIndicator />
          </ListBox.Item>
          <ListBox.Item id="kangaroo" textValue="Kangaroo">
            Kangaroo
            <ListBox.ItemIndicator />
          </ListBox.Item>
          <ListBox.Item id="elephant" textValue="Elephant">
            Elephant
            <ListBox.ItemIndicator />
          </ListBox.Item>
          <ListBox.Item id="tiger" textValue="Tiger">
            Tiger
            <ListBox.ItemIndicator />
          </ListBox.Item>
        </ListBox>
      </Select.Content>
    </Select>
  );
}

Custom Indicator

State
import {Label, ListBox, Select} from "@heroui/react";
import {Icon} from "@iconify/react";

export function CustomIndicator() {
  return (
    <Select className="w-[256px]" placeholder="Select one">
      <Label>State</Label>
      <Select.Trigger>
        <Select.Value />
        <Select.Indicator className="size-3">
          <Icon icon="gravity-ui:chevrons-expand-vertical" />
        </Select.Indicator>
      </Select.Trigger>
      <Select.Content>
        <ListBox>
          <ListBox.Item id="florida" textValue="Florida">
            Florida
            <ListBox.ItemIndicator />
          </ListBox.Item>
          <ListBox.Item id="delaware" textValue="Delaware">
            Delaware
            <ListBox.ItemIndicator />
          </ListBox.Item>
          <ListBox.Item id="california" textValue="California">
            California
            <ListBox.ItemIndicator />
          </ListBox.Item>
          <ListBox.Item id="texas" textValue="Texas">
            Texas
            <ListBox.ItemIndicator />
          </ListBox.Item>
          <ListBox.Item id="new-york" textValue="New York">
            New York
            <ListBox.ItemIndicator />
          </ListBox.Item>
          <ListBox.Item id="washington" textValue="Washington">
            Washington
            <ListBox.ItemIndicator />
          </ListBox.Item>
        </ListBox>
      </Select.Content>
    </Select>
  );
}

Required

State
Country
"use client";

import {Button, FieldError, Form, Label, ListBox, Select} from "@heroui/react";

export function Required() {
  const onSubmit = (e: React.FormEvent<HTMLFormElement>) => {
    e.preventDefault();
    const formData = new FormData(e.currentTarget);
    const data: Record<string, string> = {};

    // Convert FormData to plain object
    formData.forEach((value, key) => {
      data[key] = value.toString();
    });

    alert("Form submitted successfully!");
  };

  return (
    <Form className="flex w-[256px] flex-col gap-4" onSubmit={onSubmit}>
      <Select isRequired className="w-full" name="state" placeholder="Select one">
        <Label>State</Label>
        <Select.Trigger>
          <Select.Value />
          <Select.Indicator />
        </Select.Trigger>
        <Select.Content>
          <ListBox>
            <ListBox.Item id="florida" textValue="Florida">
              Florida
              <ListBox.ItemIndicator />
            </ListBox.Item>
            <ListBox.Item id="delaware" textValue="Delaware">
              Delaware
              <ListBox.ItemIndicator />
            </ListBox.Item>
            <ListBox.Item id="california" textValue="California">
              California
              <ListBox.ItemIndicator />
            </ListBox.Item>
            <ListBox.Item id="texas" textValue="Texas">
              Texas
              <ListBox.ItemIndicator />
            </ListBox.Item>
            <ListBox.Item id="new-york" textValue="New York">
              New York
              <ListBox.ItemIndicator />
            </ListBox.Item>
            <ListBox.Item id="washington" textValue="Washington">
              Washington
              <ListBox.ItemIndicator />
            </ListBox.Item>
          </ListBox>
        </Select.Content>
        <FieldError />
      </Select>
      <Select isRequired className="w-full" name="country" placeholder="Select a country">
        <Label>Country</Label>
        <Select.Trigger>
          <Select.Value />
          <Select.Indicator />
        </Select.Trigger>
        <Select.Content>
          <ListBox>
            <ListBox.Item id="usa" textValue="United States">
              United States
              <ListBox.ItemIndicator />
            </ListBox.Item>
            <ListBox.Item id="canada" textValue="Canada">
              Canada
              <ListBox.ItemIndicator />
            </ListBox.Item>
            <ListBox.Item id="mexico" textValue="Mexico">
              Mexico
              <ListBox.ItemIndicator />
            </ListBox.Item>
            <ListBox.Item id="uk" textValue="United Kingdom">
              United Kingdom
              <ListBox.ItemIndicator />
            </ListBox.Item>
            <ListBox.Item id="france" textValue="France">
              France
              <ListBox.ItemIndicator />
            </ListBox.Item>
            <ListBox.Item id="germany" textValue="Germany">
              Germany
              <ListBox.ItemIndicator />
            </ListBox.Item>
          </ListBox>
        </Select.Content>
        <FieldError />
      </Select>
      <Button type="submit">Submit</Button>
    </Form>
  );
}

On Surface

State
Country
"use client";

import {Button, FieldError, Form, Label, ListBox, Select, Surface} from "@heroui/react";

export function OnSurface() {
  const onSubmit = (e: React.FormEvent<HTMLFormElement>) => {
    e.preventDefault();
    const formData = new FormData(e.currentTarget);
    const data: Record<string, string> = {};

    // Convert FormData to plain object
    formData.forEach((value, key) => {
      data[key] = value.toString();
    });

    alert("Form submitted successfully!");
  };

  return (
    <Surface className="w-[320px] rounded-3xl p-6">
      <Form className="flex w-full flex-col gap-4" onSubmit={onSubmit}>
        <Select isRequired className="w-full" name="state" placeholder="Select one">
          <Label>State</Label>
          <Select.Trigger>
            <Select.Value />
            <Select.Indicator />
          </Select.Trigger>
          <Select.Content>
            <ListBox>
              <ListBox.Item id="florida" textValue="Florida">
                Florida
                <ListBox.ItemIndicator />
              </ListBox.Item>
              <ListBox.Item id="delaware" textValue="Delaware">
                Delaware
                <ListBox.ItemIndicator />
              </ListBox.Item>
              <ListBox.Item id="california" textValue="California">
                California
                <ListBox.ItemIndicator />
              </ListBox.Item>
              <ListBox.Item id="texas" textValue="Texas">
                Texas
                <ListBox.ItemIndicator />
              </ListBox.Item>
              <ListBox.Item id="new-york" textValue="New York">
                New York
                <ListBox.ItemIndicator />
              </ListBox.Item>
              <ListBox.Item id="washington" textValue="Washington">
                Washington
                <ListBox.ItemIndicator />
              </ListBox.Item>
            </ListBox>
          </Select.Content>
          <FieldError />
        </Select>
        <Select isRequired className="w-full" name="country" placeholder="Select a country">
          <Label>Country</Label>
          <Select.Trigger>
            <Select.Value />
            <Select.Indicator />
          </Select.Trigger>
          <Select.Content>
            <ListBox>
              <ListBox.Item id="usa" textValue="United States">
                United States
                <ListBox.ItemIndicator />
              </ListBox.Item>
              <ListBox.Item id="canada" textValue="Canada">
                Canada
                <ListBox.ItemIndicator />
              </ListBox.Item>
              <ListBox.Item id="mexico" textValue="Mexico">
                Mexico
                <ListBox.ItemIndicator />
              </ListBox.Item>
              <ListBox.Item id="uk" textValue="United Kingdom">
                United Kingdom
                <ListBox.ItemIndicator />
              </ListBox.Item>
              <ListBox.Item id="france" textValue="France">
                France
                <ListBox.ItemIndicator />
              </ListBox.Item>
              <ListBox.Item id="germany" textValue="Germany">
                Germany
                <ListBox.ItemIndicator />
              </ListBox.Item>
            </ListBox>
          </Select.Content>
          <FieldError />
        </Select>
        <Button type="submit">Submit</Button>
      </Form>
    </Surface>
  );
}

Custom Value

User
"use client";

import {
  Avatar,
  AvatarFallback,
  AvatarImage,
  Description,
  Label,
  ListBox,
  Select,
} from "@heroui/react";

export function CustomValue() {
  const users = [
    {
      avatarUrl: "https://heroui-assets.nyc3.cdn.digitaloceanspaces.com/avatars/blue.jpg",
      email: "bob@heroui.com",
      fallback: "B",
      id: "1",
      name: "Bob",
    },
    {
      avatarUrl: "https://heroui-assets.nyc3.cdn.digitaloceanspaces.com/avatars/green.jpg",
      email: "fred@heroui.com",
      fallback: "F",
      id: "2",
      name: "Fred",
    },
    {
      avatarUrl: "https://heroui-assets.nyc3.cdn.digitaloceanspaces.com/avatars/purple.jpg",
      email: "martha@heroui.com",
      fallback: "M",
      id: "3",
      name: "Martha",
    },
    {
      avatarUrl: "https://heroui-assets.nyc3.cdn.digitaloceanspaces.com/avatars/red.jpg",
      email: "john@heroui.com",
      fallback: "J",
      id: "4",
      name: "John",
    },
    {
      avatarUrl: "https://heroui-assets.nyc3.cdn.digitaloceanspaces.com/avatars/orange.jpg",
      email: "jane@heroui.com",
      fallback: "J",
      id: "5",
      name: "Jane",
    },
  ];

  return (
    <Select className="w-[256px]" placeholder="Select a user">
      <Label>User</Label>
      <Select.Trigger>
        <Select.Value>
          {({defaultChildren, isPlaceholder, state}) => {
            if (isPlaceholder || state.selectedItems.length === 0) {
              return defaultChildren;
            }

            const selectedItems = state.selectedItems;

            if (selectedItems.length > 1) {
              return `${selectedItems.length} users selected`;
            }

            const selectedItem = users.find((user) => user.id === selectedItems[0].key);

            if (!selectedItem) {
              return defaultChildren;
            }

            return (
              <div className="flex items-center gap-2">
                <Avatar className="size-4" size="sm">
                  <AvatarImage src={selectedItem.avatarUrl} />
                  <AvatarFallback>{selectedItem.fallback}</AvatarFallback>
                </Avatar>
                <span>{selectedItem.name}</span>
              </div>
            );
          }}
        </Select.Value>
        <Select.Indicator />
      </Select.Trigger>
      <Select.Content>
        <ListBox>
          {users.map((user) => (
            <ListBox.Item key={user.id} id={user.id} textValue={user.name}>
              <Avatar size="sm">
                <AvatarImage src={user.avatarUrl} />
                <AvatarFallback>{user.fallback}</AvatarFallback>
              </Avatar>
              <div className="flex flex-col">
                <Label>{user.name}</Label>
                <Description>{user.email}</Description>
              </div>
              <ListBox.ItemIndicator />
            </ListBox.Item>
          ))}
        </ListBox>
      </Select.Content>
    </Select>
  );
}

Controlled

State (controlled)

Selected: California

"use client";

import type {Key} from "react-aria-components";

import {Label, ListBox, Select} from "@heroui/react";
import {useState} from "react";

export function Controlled() {
  const states = [
    {
      id: "california",
      name: "California",
    },
    {
      id: "texas",
      name: "Texas",
    },
    {
      id: "florida",
      name: "Florida",
    },
    {
      id: "new-york",
      name: "New York",
    },
    {
      id: "illinois",
      name: "Illinois",
    },
    {
      id: "pennsylvania",
      name: "Pennsylvania",
    },
  ];

  const [state, setState] = useState<Key | null>("california");

  const selectedState = states.find((s) => s.id === state);

  return (
    <div className="space-y-2">
      <Select
        className="w-[256px]"
        placeholder="Select a state"
        value={state}
        onChange={(value) => setState(value)}
      >
        <Label>State (controlled)</Label>
        <Select.Trigger>
          <Select.Value />
          <Select.Indicator />
        </Select.Trigger>
        <Select.Content>
          <ListBox>
            {states.map((state) => (
              <ListBox.Item key={state.id} id={state.id} textValue={state.name}>
                {state.name}
                <ListBox.ItemIndicator />
              </ListBox.Item>
            ))}
          </ListBox>
        </Select.Content>
      </Select>
      <p className="text-muted text-sm">Selected: {selectedState?.name || "None"}</p>
    </div>
  );
}

Controlled Multiple

States (controlled multiple)

Selected: california, texas

"use client";

import type {Selection} from "@react-types/shared";

import {Label, ListBox, Select} from "@heroui/react";
import {useState} from "react";

export function ControlledMultiple() {
  const [selected, setSelected] = useState<Selection>(new Set(["california", "texas"]));

  const selectedItems = Array.from(selected);

  return (
    <div className="space-y-4">
      <Select className="w-[256px]" placeholder="Select states" selectionMode="multiple">
        <Label>States (controlled multiple)</Label>
        <Select.Trigger>
          <Select.Value />
          <Select.Indicator />
        </Select.Trigger>
        <Select.Content>
          <ListBox
            selectedKeys={selected}
            selectionMode="multiple"
            onSelectionChange={(keys) => setSelected(keys as Selection)}
          >
            <ListBox.Item id="california" textValue="California">
              California
              <ListBox.ItemIndicator />
            </ListBox.Item>
            <ListBox.Item id="texas" textValue="Texas">
              Texas
              <ListBox.ItemIndicator />
            </ListBox.Item>
            <ListBox.Item id="florida" textValue="Florida">
              Florida
              <ListBox.ItemIndicator />
            </ListBox.Item>
            <ListBox.Item id="new-york" textValue="New York">
              New York
              <ListBox.ItemIndicator />
            </ListBox.Item>
            <ListBox.Item id="illinois" textValue="Illinois">
              Illinois
              <ListBox.ItemIndicator />
            </ListBox.Item>
            <ListBox.Item id="pennsylvania" textValue="Pennsylvania">
              Pennsylvania
              <ListBox.ItemIndicator />
            </ListBox.Item>
          </ListBox>
        </Select.Content>
      </Select>
      <p className="text-sm text-neutral-500">
        Selected: {selectedItems.length > 0 ? selectedItems.join(", ") : "None"}
      </p>
    </div>
  );
}

Controlled Open State

State

Select is closed

"use client";

import {Button, Label, ListBox, Select} from "@heroui/react";
import {useState} from "react";

export function ControlledOpenState() {
  const [isOpen, setIsOpen] = useState(false);

  return (
    <div className="space-y-4">
      <Select
        className="w-[256px]"
        isOpen={isOpen}
        placeholder="Select one"
        onOpenChange={setIsOpen}
      >
        <Label>State</Label>
        <Select.Trigger>
          <Select.Value />
          <Select.Indicator />
        </Select.Trigger>
        <Select.Content>
          <ListBox>
            <ListBox.Item id="florida" textValue="Florida">
              Florida
              <ListBox.ItemIndicator />
            </ListBox.Item>
            <ListBox.Item id="delaware" textValue="Delaware">
              Delaware
              <ListBox.ItemIndicator />
            </ListBox.Item>
            <ListBox.Item id="california" textValue="California">
              California
              <ListBox.ItemIndicator />
            </ListBox.Item>
            <ListBox.Item id="texas" textValue="Texas">
              Texas
              <ListBox.ItemIndicator />
            </ListBox.Item>
            <ListBox.Item id="new-york" textValue="New York">
              New York
              <ListBox.ItemIndicator />
            </ListBox.Item>
            <ListBox.Item id="washington" textValue="Washington">
              Washington
              <ListBox.ItemIndicator />
            </ListBox.Item>
          </ListBox>
        </Select.Content>
      </Select>
      <Button onPress={() => setIsOpen(!isOpen)}>{isOpen ? "Close" : "Open"} Select</Button>
      <p className="text-sm text-neutral-500">Select is {isOpen ? "open" : "closed"}</p>
    </div>
  );
}

Asynchronous Loading

Pick a Pokemon
"use client";

import {Label, ListBox, Select, Spinner} from "@heroui/react";
import {useAsyncList} from "@react-stately/data";
import {Collection, ListBoxLoadMoreItem} from "react-aria-components";

interface Pokemon {
  name: string;
}

export function AsynchronousLoading() {
  const list = useAsyncList<Pokemon>({
    async load({cursor, signal}) {
      const res = await fetch(cursor || `https://pokeapi.co/api/v2/pokemon`, {signal});
      const json = await res.json();

      return {
        cursor: json.next,
        items: json.results,
      };
    },
  });

  return (
    <Select className="w-[256px]" placeholder="Select a Pokemon">
      <Label>Pick a Pokemon</Label>
      <Select.Trigger>
        <Select.Value />
        <Select.Indicator />
      </Select.Trigger>
      <Select.Content>
        <ListBox>
          <Collection items={list.items}>
            {(item: Pokemon) => (
              <ListBox.Item id={item.name} textValue={item.name}>
                {item.name}
                <ListBox.ItemIndicator />
              </ListBox.Item>
            )}
          </Collection>
          <ListBoxLoadMoreItem
            isLoading={list.loadingState === "loadingMore"}
            onLoadMore={list.loadMore}
          >
            <div className="flex items-center justify-center gap-2 py-2">
              <Spinner size="sm" />
              <span className="text-sm text-neutral-500">Loading more...</span>
            </div>
          </ListBoxLoadMoreItem>
        </ListBox>
      </Select.Content>
    </Select>
  );
}

Disabled

State
Countries to Visit
import {Label, ListBox, Select} from "@heroui/react";

export function Disabled() {
  return (
    <div className="flex flex-col gap-4">
      <Select isDisabled className="w-[256px]" defaultValue="california" placeholder="Select one">
        <Label>State</Label>
        <Select.Trigger>
          <Select.Value />
          <Select.Indicator />
        </Select.Trigger>
        <Select.Content>
          <ListBox>
            <ListBox.Item id="florida" textValue="Florida">
              Florida
              <ListBox.ItemIndicator />
            </ListBox.Item>
            <ListBox.Item id="delaware" textValue="Delaware">
              Delaware
              <ListBox.ItemIndicator />
            </ListBox.Item>
            <ListBox.Item id="california" textValue="California">
              California
              <ListBox.ItemIndicator />
            </ListBox.Item>
            <ListBox.Item id="texas" textValue="Texas">
              Texas
              <ListBox.ItemIndicator />
            </ListBox.Item>
            <ListBox.Item id="new-york" textValue="New York">
              New York
              <ListBox.ItemIndicator />
            </ListBox.Item>
            <ListBox.Item id="washington" textValue="Washington">
              Washington
              <ListBox.ItemIndicator />
            </ListBox.Item>
          </ListBox>
        </Select.Content>
      </Select>
      <Select
        isDisabled
        className="w-[256px]"
        defaultValue={["argentina", "japan", "france"]}
        placeholder="Select countries"
        selectionMode="multiple"
      >
        <Label>Countries to Visit</Label>
        <Select.Trigger>
          <Select.Value />
          <Select.Indicator />
        </Select.Trigger>
        <Select.Content>
          <ListBox>
            <ListBox.Item id="argentina" textValue="Argentina">
              Argentina
              <ListBox.ItemIndicator />
            </ListBox.Item>
            <ListBox.Item id="venezuela" textValue="Venezuela">
              Venezuela
              <ListBox.ItemIndicator />
            </ListBox.Item>
            <ListBox.Item id="japan" textValue="Japan">
              Japan
              <ListBox.ItemIndicator />
            </ListBox.Item>
            <ListBox.Item id="france" textValue="France">
              France
              <ListBox.ItemIndicator />
            </ListBox.Item>
            <ListBox.Item id="italy" textValue="Italy">
              Italy
              <ListBox.ItemIndicator />
            </ListBox.Item>
            <ListBox.Item id="spain" textValue="Spain">
              Spain
              <ListBox.ItemIndicator />
            </ListBox.Item>
          </ListBox>
        </Select.Content>
      </Select>
    </div>
  );
}

Styling

Passing Tailwind CSS classes

import { Select } from '@heroui/react';

function CustomSelect() {
  return (
    <Select className="w-full">
      <Label>State</Label>
      <Select.Trigger className="border rounded-lg p-2 bg-surface">
        <Select.Value />
        <Select.Indicator />
      </Select.Trigger>
      <Select.Content>
        <ListBox>
          <ListBox.Item id="1" textValue="Item 1" className="hover:bg-surface-secondary">
            Item 1
          </ListBox.Item>
        </ListBox>
      </Select.Content>
    </Select>
  );
}

Customizing the component classes

To customize the Select component classes, you can use the @layer components directive.
Learn more.

@layer components {
  .select {
    @apply flex flex-col gap-1;
  }

  .select__trigger {
    @apply rounded-lg border border-border bg-surface p-2;
  }

  .select__value {
    @apply text-current;
  }

  .select__indicator {
    @apply text-muted;
  }

  .select__content {
    @apply rounded-lg border border-border bg-surface p-2;
  }
}

HeroUI follows the BEM methodology to ensure component variants and states are reusable and easy to customize.

CSS Classes

The Select component uses these CSS classes (View source styles):

Base Classes

  • .select - Base select container
  • .select__trigger - The button that triggers the select
  • .select__value - The displayed value or placeholder
  • .select__indicator - The dropdown indicator icon
  • .select__content - The popover content container

Variant Classes

  • .select__trigger--on-surface - On surface variant styling

State Classes

  • .select[data-invalid="true"] - Invalid state
  • .select__trigger[data-focus-visible="true"] - Focused trigger state
  • .select__trigger[data-disabled="true"] - Disabled trigger state
  • .select__value[data-placeholder="true"] - Placeholder state
  • .select__indicator[data-open="true"] - Open indicator state

Interactive States

The component supports both CSS pseudo-classes and data attributes for flexibility:

  • Hover: :hover or [data-hovered="true"] on trigger
  • Focus: :focus-visible or [data-focus-visible="true"] on trigger
  • Disabled: :disabled or [data-disabled="true"] on select
  • Open: [data-open="true"] on indicator

API Reference

Select Props

PropTypeDefaultDescription
placeholderstring'Select an item'Temporary text that occupies the select when it is empty
selectionMode"single" | "multiple""single"Whether single or multiple selection is enabled
isOpenboolean-Sets the open state of the menu (controlled)
defaultOpenboolean-Sets the default open state of the menu (uncontrolled)
onOpenChange(isOpen: boolean) => void-Handler called when the open state changes
disabledKeysIterable<Key>-Keys of disabled items
isDisabledboolean-Whether the select is disabled
valueKey | Key[] | null-Current value (controlled)
defaultValueKey | Key[] | null-Default value (uncontrolled)
onChange(value: Key | Key[] | null) => void-Handler called when the value changes
isRequiredboolean-Whether user input is required
isInvalidboolean-Whether the select value is invalid
namestring-The name of the input, used when submitting an HTML form
autoCompletestring-Describes the type of autocomplete functionality
isOnSurfaceboolean-Whether the select is displayed on a surface component
classNamestring-Additional CSS classes
childrenReactNode | RenderFunction-Select content or render function

Select.Trigger Props

PropTypeDefaultDescription
classNamestring-Additional CSS classes
childrenReactNode | RenderFunction-Trigger content or render function

Select.Value Props

PropTypeDefaultDescription
classNamestring-Additional CSS classes
childrenReactNode | RenderFunction-Value content or render function

Select.Indicator Props

PropTypeDefaultDescription
classNamestring-Additional CSS classes
childrenReactNode-Custom indicator content

Select.Content Props

PropTypeDefaultDescription
placement"bottom" | "bottom left" | "bottom right" | "bottom start" | "bottom end" | "top" | "top left" | "top right" | "top start" | "top end" | "left" | "left top" | "left bottom" | "start" | "start top" | "start bottom" | "right" | "right top" | "right bottom" | "end" | "end top" | "end bottom""bottom"Placement of the popover relative to the trigger
classNamestring-Additional CSS classes
childrenReactNode-Content children

RenderProps

When using render functions with Select.Value, these values are provided:

PropTypeDescription
defaultChildrenReactNodeThe default rendered value
isPlaceholderbooleanWhether the value is a placeholder
stateSelectStateThe state of the select
selectedItemsNode[]The currently selected items

Examples

Basic Usage

import { Select, Label, ListBox } from '@heroui/react';

<Select className="w-[256px]" placeholder="Select one">
  <Label>State</Label>
  <Select.Trigger>
    <Select.Value />
    <Select.Indicator />
  </Select.Trigger>
  <Select.Content>
    <ListBox>
      <ListBox.Item id="florida" textValue="Florida">
        Florida
        <ListBox.ItemIndicator />
      </ListBox.Item>
      <ListBox.Item id="california" textValue="California">
        California
        <ListBox.ItemIndicator />
      </ListBox.Item>
    </ListBox>
  </Select.Content>
</Select>

With Sections

import { Select, Label, ListBox, Header, Separator } from '@heroui/react';

<Select className="w-[256px]" placeholder="Select a country">
  <Label>Country</Label>
  <Select.Trigger>
    <Select.Value />
    <Select.Indicator />
  </Select.Trigger>
  <Select.Content>
    <ListBox>
      <ListBox.Section>
        <Header>North America</Header>
        <ListBox.Item id="usa" textValue="United States">
          United States
          <ListBox.ItemIndicator />
        </ListBox.Item>
      </ListBox.Section>
      <Separator />
      <ListBox.Section>
        <Header>Europe</Header>
        <ListBox.Item id="uk" textValue="United Kingdom">
          United Kingdom
          <ListBox.ItemIndicator />
        </ListBox.Item>
      </ListBox.Section>
    </ListBox>
  </Select.Content>
</Select>

Controlled Selection

import type { Key } from '@heroui/react';

import { Select, Label, ListBox } from '@heroui/react';
import { useState } from 'react';

function ControlledSelect() {
  const [value, setValue] = useState<Key | null>('california');

  return (
    <Select
      className="w-[256px]"
      placeholder="Select a state"
      value={value}
      onChange={setValue}
    >
      <Label>State</Label>
      <Select.Trigger>
        <Select.Value />
        <Select.Indicator />
      </Select.Trigger>
      <Select.Content>
        <ListBox>
          <ListBox.Item id="california" textValue="California">
            California
            <ListBox.ItemIndicator />
          </ListBox.Item>
          <ListBox.Item id="texas" textValue="Texas">
            Texas
            <ListBox.ItemIndicator />
          </ListBox.Item>
        </ListBox>
      </Select.Content>
    </Select>
  );
}

Custom Value Display

import { Select, Label, ListBox, Avatar, AvatarImage, AvatarFallback } from '@heroui/react';

<Select className="w-[256px]" placeholder="Select a user">
  <Label>User</Label>
  <Select.Trigger>
    <Select.Value>
      {({defaultChildren, isPlaceholder, state}) => {
        if (isPlaceholder || state.selectedItems.length === 0) {
          return defaultChildren;
        }

        const selectedItem = users.find((user) => user.id === state.selectedItems[0].key);

        if (!selectedItem) {
          return defaultChildren;
        }

        return (
          <div className="flex items-center gap-2">
            <Avatar className="size-4" size="sm">
              <AvatarImage src={selectedItem.avatarUrl} />
              <AvatarFallback>{selectedItem.fallback}</AvatarFallback>
            </Avatar>
            <span>{selectedItem.name}</span>
          </div>
        );
      }}
    </Select.Value>
    <Select.Indicator />
  </Select.Trigger>
  <Select.Content>
    <ListBox>
      {/* ListBox items */}
    </ListBox>
  </Select.Content>
</Select>

Accessibility

The Select component implements the ARIA listbox pattern and provides:

  • Full keyboard navigation support
  • Screen reader announcements for selection changes
  • Proper focus management
  • Support for disabled states
  • Typeahead search functionality
  • HTML form integration

For more information, see the React Aria Select documentation.