Select

Displays a list of options for the user to pick from, triggered by a button.

Anatomy

Import and assemble the component:

1import { Select } from "@raystack/apsara";
2
3<Select>
4 <Select.Label />
5 <Select.Trigger>
6 <Select.Value />
7 </Select.Trigger>
8 <Select.Content>
9 <Select.Status />
10 <Select.Empty />
11 <Select.Group>
12 <Select.GroupLabel />
13 <Select.Item />
14 </Select.Group>
15 <Select.Separator />
16 </Select.Content>
17</Select>

Usage

Appearance first, meaning size and variant, then how many items can be chosen, and who owns the value.

Basic Select

A trigger and a list of items. Select.Value renders the current selection in the trigger. A check mark shows the selected item in the list. In multiple mode, each item has a checkbox instead.

Pass items to the root so Select.Value can show the label of the selected value. It takes { value, label }[] or a value-to-label record. The list mounts only when it opens, so without items the trigger shows the raw value.

1<Select items={{ apple: "Apple", banana: "Banana" }}>
2 <Select.Trigger aria-label="Fruit selection">
3 <Select.Value placeholder="Select a fruit" />
4 </Select.Trigger>
5 <Select.Content>
6 <Select.Item value="apple">Apple</Select.Item>
7 <Select.Item value="banana">Banana</Select.Item>
8 </Select.Content>
9</Select>

Icon

Pass leadingIcon to Select.Item to show an icon before the item text.

1<Select
2 items={{ apple: "Apple", banana: "Banana", grape: "Grape", orange: "Orange" }}
3>
4 <Select.Trigger aria-label="Fruit selection">
5 <Select.Value placeholder="Select a fruit" />
6 </Select.Trigger>
7 <Select.Content>
8 <Select.Item value="apple" leadingIcon={<Info size={16} />}>
9 Apple
10 </Select.Item>
11 <Select.Item value="banana" leadingIcon={<X size={16} />}>
12 Banana
13 </Select.Item>
14 <Select.Item value="grape" leadingIcon={<Home size={16} />}>

To show the icon in the trigger too, pass a function as the child of Select.Value. It receives the selected value.

1(function IconValue() {
2 const fruits = {
3 apple: { label: "Apple", icon: <Info size={16} /> },
4 banana: { label: "Banana", icon: <Home size={16} /> },
5 };
6
7 return (
8 <Select defaultValue="apple">
9 <Select.Trigger>
10 <Select.Value placeholder="Select a fruit">
11 {(value) => (
12 <Flex align="center" gap={2}>
13 {fruits[value].icon}
14 {fruits[value].label}

Label

Select.Label renders a visible label linked to the trigger. Clicking it focuses the trigger.

1<Flex direction="column" gap={2}>
2 <Select items={{ apple: "Apple", banana: "Banana" }}>
3 <Select.Label>Fruit</Select.Label>
4 <Select.Trigger>
5 <Select.Value placeholder="Select a fruit" />
6 </Select.Trigger>
7 <Select.Content>
8 <Select.Item value="apple">Apple</Select.Item>
9 <Select.Item value="banana">Banana</Select.Item>
10 </Select.Content>
11 </Select>
12</Flex>

Size

Two sizes. medium is the default; small fits toolbars and table filters.

1<Flex align="center" gap={9}>
2 <Select items={{ "1": "Option 1", "2": "Option 2" }}>
3 <Select.Trigger size="small">
4 <Select.Value placeholder="Small select" />
5 </Select.Trigger>
6 <Select.Content>
7 <Select.Item value="1">Option 1</Select.Item>
8 <Select.Item value="2">Option 2</Select.Item>
9 </Select.Content>
10 </Select>
11 <Select items={{ "1": "Option 1", "2": "Option 2" }}>
12 <Select.Trigger>
13 <Select.Value placeholder="Medium select" />
14 </Select.Trigger>

Variant

outline (the default) draws a bordered control. text removes the border for use inside a toolbar or beside other text.

1<Select items={{ all: "All", active: "Active", inactive: "Inactive" }}>
2 <Select.Trigger>
3 <Select.Value placeholder="Select..." />
4 </Select.Trigger>
5 <Select.Content>
6 <Select.Item value="all">All</Select.Item>
7 <Select.Item value="active">Active</Select.Item>
8 <Select.Item value="inactive">Inactive</Select.Item>
9 </Select.Content>
10</Select>

With Separator

Select.Separator draws a rule between groups of items.

1<Select
2 items={{ "1": "Option 1", "2": "Option 2", "3": "Option 3", "4": "Option 4" }}
3>
4 <Select.Trigger>
5 <Select.Value placeholder="Select..." />
6 </Select.Trigger>
7 <Select.Content>
8 <Select.Group>
9 <Select.Item value="1">Option 1</Select.Item>
10 <Select.Item value="2">Option 2</Select.Item>
11 </Select.Group>
12 <Select.Separator />
13 <Select.Group>
14 <Select.Item value="3">Option 3</Select.Item>

Multiple selection

To enable multiple selection, pass the multiple prop to the Select root element.

When multiple selection is enabled, the value, onValueChange, and defaultValue will be an array of strings.

1<Select
2 multiple
3 items={Array.from({ length: 10 }, (_, i) => ({
4 value: String(i + 1),
5 label: "Option " + (i + 1),
6 }))}
7>
8 <Select.Trigger>
9 <Select.Value placeholder="Select..." />
10 </Select.Trigger>
11 <Select.Content>
12 <Select.Item value="1">Option 1</Select.Item>
13 <Select.Item value="2">Option 2</Select.Item>
14 <Select.Item value="3">Option 3</Select.Item>

Autocomplete

To enable autocomplete, pass the autocomplete prop to the Select root element.

With items, Base UI filters by label. Without items, the select filters items with a simple text match. For full control, set autocompleteMode="manual" and filter the items yourself.

Select.Empty shows its content only when no item matches the search. It needs items on the root. Select.Status is a polite live region for messages such as a result count or a loading state. Both work only in autocomplete mode.

1<Select
2 autocomplete
3 items={{
4 apple: "Apple",
5 banana: "Banana",
6 blueberry: "Blueberry",
7 grapes: "Grapes",
8 pineapple: "Pineapple",
9 }}
10>
11 <Select.Trigger>
12 <Select.Value placeholder="Select a fruit" />
13 </Select.Trigger>
14 <Select.Content>

Controlled

Pass value with onValueChange to own the selection. Do this when the value comes from a form, a URL, or another control on the page.

1(function ControlledSelect() {
2 const [fruit, setFruit] = React.useState("apple");
3
4 return (
5 <Flex direction="column" gap={5}>
6 <Select
7 value={fruit}
8 onValueChange={setFruit}
9 items={{ apple: "Apple", banana: "Banana", grapes: "Grapes" }}
10 >
11 <Select.Trigger width={200}>
12 <Select.Value />
13 </Select.Trigger>
14 <Select.Content>

API Reference

The trigger, and the parts of the list it opens.

Root

The Select component is composed of several parts, each with their own props.

The root element is the parent component that holds the select. Using the autocomplete prop, you can enable autocomplete functionality.

Prop

Type

Trigger

The button that triggers the Select.

Prop

Type

Content

The container that holds the Select items.

Prop

Type

Set alignItemWithTrigger to open the list over the trigger, with the selected item lined up on the trigger's value. Base UI turns it off for touch input and when there is not enough space, and then places the list the normal way. side and align only apply when the list is placed the normal way.

Item

Individual clickable options within the Select.

Prop

Type

Group

A way to group related Select items together.

Prop

Type

Value

Shows the label of the selected value, or the placeholder.

Prop

Type

Label

A visible label linked to the trigger.

Prop

Type

GroupLabel

The label of a Select.Group. Use it only inside Select.Group.

Prop

Type

Empty

Shows its content when no item matches the search. Autocomplete mode only.

Prop

Type

Status

A polite live region for status messages. Autocomplete mode only.

Prop

Type

Separator

Visual divider between Select items or groups.

Prop

Type

Slots

Every rendered part carries a stable data-slot attribute for styling and testing:

SlotElement
select-triggerThe trigger button that opens the menu
select-trigger-contentFlex wrapper around the trigger's children
select-trigger-iconThe chevron dropdown icon in the trigger
select-labelThe label linked to the trigger
select-valueThe <span> showing the selected label or placeholder
select-value-contentWrapper around the chips in multiple mode
select-value-overflowThe "+N" overflow count for multiple values (when they don't all fit)
select-positionerThe floating positioner for the popup
select-contentThe popup container
select-searchThe search input (when autocomplete is enabled)
select-listThe scrollable list of items
select-groupA group of items
select-group-labelThe label of a group
select-emptyThe message shown when no item matches (autocomplete only)
select-statusThe live region for status messages (autocomplete only)
select-separatorA divider between items or groups
select-itemAn individual option row
select-item-iconLeading icon on an item (when set)
select-item-textThe text label of an item
select-item-indicatorThe check mark on the selected item (single selection only)

Accessibility

The Select component follows WAI-ARIA guidelines:

  • Trigger has role combobox
  • Content has role listbox
  • Items have role option
  • ARIA labels and descriptions