# Select **Category**: react **URL**: https://www.heroui.com/docs/react/components/select **Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/react/components/(pickers)/select.mdx > A select displays a collapsible list of options and allows a user to select one of them *** ## Import ```tsx import { Select } from "@heroui/react"; ``` ### Usage ```tsx import {Label, ListBox, Select} from "@heroui/react"; export function Default() { return ( ); } ``` ### Anatomy Import the Select component and access all parts using dot notation. ```tsx import {Select, Label, Description, Header, ListBox, Separator} from "@heroui/react"; export default () => ( ); ``` ### With Description ```tsx import {Description, Label, ListBox, Select} from "@heroui/react"; export function WithDescription() { return ( ); } ``` ### Multiple Select ```tsx import {Label, ListBox, Select} from "@heroui/react"; export function MultipleSelect() { return ( ); } ``` ### With Sections ```tsx import {Header, Label, ListBox, Select, Separator} from "@heroui/react"; export function WithSections() { return ( ); } ``` ### With Disabled Options ```tsx import {Label, ListBox, Select} from "@heroui/react"; export function WithDisabledOptions() { return ( ); } ``` ### Custom Indicator ```tsx import {ChevronsExpandVertical} from "@gravity-ui/icons"; import {Label, ListBox, Select} from "@heroui/react"; export function CustomIndicator() { return ( ); } ``` ### Required ```tsx "use client"; import {Button, FieldError, Form, Label, ListBox, Select} from "@heroui/react"; export function Required() { const onSubmit = (e: React.FormEvent) => { e.preventDefault(); const formData = new FormData(e.currentTarget); const data: Record = {}; // Convert FormData to plain object formData.forEach((value, key) => { data[key] = value.toString(); }); alert("Form submitted successfully!"); }; return (
); } ``` ### Full Width ```tsx import {Label, ListBox, Select} from "@heroui/react"; export function FullWidth() { return (
); } ``` ### Variants The Select component supports two visual variants: - **`primary`** (default) - Standard styling with shadow, suitable for most use cases - **`secondary`** - Lower emphasis variant without shadow, suitable for use in Surface components ```tsx import {Label, ListBox, Select} from "@heroui/react"; export function Variants() { return (
); } ``` ### In Surface When used inside a [Surface](/docs/components/surface) component, use `variant="secondary"` to apply the lower emphasis variant suitable for surface backgrounds. ```tsx "use client"; import {Button, FieldError, Form, Label, ListBox, Select, Surface} from "@heroui/react"; export function OnSurface() { const onSubmit = (e: React.FormEvent) => { e.preventDefault(); const formData = new FormData(e.currentTarget); const data: Record = {}; // Convert FormData to plain object formData.forEach((value, key) => { data[key] = value.toString(); }); alert("Form submitted successfully!"); }; return (
); } ``` ### Custom Value ```tsx "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 ( ); } ``` ### Controlled ```tsx "use client"; import type {Key} from "@heroui/react"; 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("california"); const selectedState = states.find((s) => s.id === state); return (

Selected: {selectedState?.name || "None"}

); } ``` ### Controlled Multiple ```tsx "use client"; import type {Key} from "@heroui/react"; import {Label, ListBox, Select} from "@heroui/react"; import React from "react"; export function ControlledMultiple() { const [selected, setSelected] = React.useState(["california", "texas"]); return (

Selected: {selected.length > 0 ? selected.join(", ") : "None"}

); } ``` ### Controlled Open State ```tsx "use client"; import {Button, Label, ListBox, Select} from "@heroui/react"; import {useState} from "react"; export function ControlledOpenState() { const [isOpen, setIsOpen] = useState(false); return (

Select is {isOpen ? "open" : "closed"}

); } ``` ### Asynchronous Loading ```tsx "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({ 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 ( ); } ``` ### Disabled ```tsx import {Label, ListBox, Select} from "@heroui/react"; export function Disabled() { return (
); } ``` ## Related Components - **Listbox**: Scrollable list of selectable items - **Popover**: Displays content in context with a trigger - **Label**: Accessible label for form controls ### Custom Render Function ```tsx "use client"; import {Label, ListBox, Select} from "@heroui/react"; export function CustomRenderFunction() { return ( ); } ``` ## Styling ### Passing Tailwind CSS classes ```tsx import {Select} from "@heroui/react"; function CustomSelect() { return ( ); } ``` ### Customizing the component classes To customize the Select component classes, you can use the `@layer components` directive.
[Learn more](https://tailwindcss.com/docs/adding-custom-styles#adding-component-classes). ```css @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__popover { @apply rounded-lg border border-border bg-surface p-2; } } ``` HeroUI follows the [BEM](https://getbem.com/) 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](https://github.com/heroui-inc/heroui/blob/v3/packages/styles/components/select.css)): #### 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__popover` - The popover container #### Variant Classes - `.select--primary` - Primary variant with shadow (default) - `.select--secondary` - Secondary variant without shadow, suitable for use in surfaces #### 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 | Prop | Type | Default | Description | | --------------- | --------------------------------------- | ------------------ | -------------------------------------------------------- | | `placeholder` | `string` | `'Select an item'` | Temporary text that occupies the select when it is empty | | `selectionMode` | `"single" \| "multiple"` | `"single"` | Whether single or multiple selection is enabled | | `isOpen` | `boolean` | - | Sets the open state of the menu (controlled) | | `defaultOpen` | `boolean` | - | Sets the default open state of the menu (uncontrolled) | | `onOpenChange` | `(isOpen: boolean) => void` | - | Handler called when the open state changes | | `disabledKeys` | `Iterable` | - | Keys of disabled items | | `isDisabled` | `boolean` | - | Whether the select is disabled | | `value` | `Key \| Key[] \| null` | - | Current value (controlled) | | `defaultValue` | `Key \| Key[] \| null` | - | Default value (uncontrolled) | | `onChange` | `(value: Key \| Key[] \| null) => void` | - | Handler called when the value changes | | `isRequired` | `boolean` | - | Whether user input is required | | `isInvalid` | `boolean` | - | Whether the select value is invalid | | `name` | `string` | - | The name of the input, used when submitting an HTML form | | `autoComplete` | `string` | - | Describes the type of autocomplete functionality | | `fullWidth` | `boolean` | `false` | Whether the select should take full width of its container | | `variant` | `"primary" \| "secondary"` | `"primary"` | Visual variant of the component. `primary` is the default style with shadow. `secondary` is a lower emphasis variant without shadow, suitable for use in surfaces. | | `className` | `string` | - | Additional CSS classes | | `children` | `ReactNode \| RenderFunction` | - | Select content or render function | | `render` | `DOMRenderFunction` | - | Overrides the default DOM element with a custom render function.| ### Select.Trigger Props | Prop | Type | Default | Description | | ----------- | ----------------------------- | ------- | ---------------------------------- | | `className` | `string` | - | Additional CSS classes | | `children` | `ReactNode \| RenderFunction` | - | Trigger content or render function | ### Select.Value Props | Prop | Type | Default | Description | | ----------- | ----------------------------- | ------- | -------------------------------- | | `className` | `string` | - | Additional CSS classes | | `children` | `ReactNode \| RenderFunction` | - | Value content or render function | | `render` | `DOMRenderFunction` | - | Overrides the default DOM element with a custom render function.| ### Select.Indicator Props | Prop | Type | Default | Description | | ----------- | ----------- | ------- | ------------------------ | | `className` | `string` | - | Additional CSS classes | | `children` | `ReactNode` | - | Custom indicator content | ### Select.Popover Props | Prop | Type | Default | Description | | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------- | ------------------------------------------------ | | `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 | | `className` | `string` | - | Additional CSS classes | | `children` | `ReactNode` | - | Content children | ### RenderProps When using render functions with Select.Value, these values are provided: | Prop | Type | Description | | ----------------- | ------------- | ---------------------------------- | | `defaultChildren` | `ReactNode` | The default rendered value | | `isPlaceholder` | `boolean` | Whether the value is a placeholder | | `state` | `SelectState` | The state of the select | | `selectedItems` | `Node[]` | The currently selected items | ## 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](https://react-spectrum.adobe.com/react-aria/Select.html).