Ark Logo

Select

Displays a list of options for the user to pick from.

Anatomy

To set up the select correctly, you'll need to understand its anatomy and how we name its parts.

Each part includes a data-part attribute to help identify them in the DOM.

Examples

Learn how to use the Select component in your project. Let's take a look at the most basic example:

import { ChevronDownIcon } from 'lucide-react'
import { Portal, Select } from '@ark-ui/react'

export const Basic = () => {
  const items = ['React', 'Solid', 'Vue']
  return (
    <Select.Root items={items}>
      <Select.Label>Framework</Select.Label>
      <Select.Control>
        <Select.Trigger>
          <Select.ValueText placeholder="Select a Framework" />
          <Select.Indicator>
            <ChevronDownIcon />
          </Select.Indicator>
        </Select.Trigger>
        <Select.ClearTrigger>Clear</Select.ClearTrigger>
      </Select.Control>
      <Portal>
        <Select.Positioner>
          <Select.Content>
            <Select.ItemGroup>
              <Select.ItemGroupLabel>Frameworks</Select.ItemGroupLabel>
              {items.map((item) => (
                <Select.Item key={item} item={item}>
                  <Select.ItemText>{item}</Select.ItemText>
                  <Select.ItemIndicator>✓</Select.ItemIndicator>
                </Select.Item>
              ))}
            </Select.ItemGroup>
          </Select.Content>
        </Select.Positioner>
      </Portal>
      <Select.HiddenSelect />
    </Select.Root>
  )
}

Advanced Customization

For advanced customizations and item properties like disabled:

import { ChevronDownIcon } from 'lucide-react'
import { Portal, Select } from '@ark-ui/react'

export const Advanced = () => {
  type Item = { label: string; value: string; disabled?: boolean }
  const items: Item[] = [
    { label: 'React', value: 'react' },
    { label: 'Solid', value: 'solid' },
    { label: 'Vue', value: 'vue' },
    { label: 'Svelte', value: 'svelte', disabled: true },
  ]
  return (
    <Select.Root items={items}>
      <Select.Label>Framework</Select.Label>
      <Select.Control>
        <Select.Trigger>
          <Select.ValueText placeholder="Select a Framework" />
          <Select.Indicator>
            <ChevronDownIcon />
          </Select.Indicator>
        </Select.Trigger>
        <Select.ClearTrigger>Clear</Select.ClearTrigger>
      </Select.Control>
      <Portal>
        <Select.Positioner>
          <Select.Content>
            <Select.ItemGroup>
              <Select.ItemGroupLabel>Frameworks</Select.ItemGroupLabel>
              {items.map((item) => (
                <Select.Item key={item.value} item={item}>
                  <Select.ItemText>{item.label}</Select.ItemText>
                  <Select.ItemIndicator>✓</Select.ItemIndicator>
                </Select.Item>
              ))}
            </Select.ItemGroup>
          </Select.Content>
        </Select.Positioner>
      </Portal>
      <Select.HiddenSelect />
    </Select.Root>
  )
}

Multiple Selection

To enable multiple item selection:

import { ChevronDownIcon } from 'lucide-react'
import { Portal, Select } from '@ark-ui/react'

export const Multiple = () => {
  type Item = { label: string; value: string; disabled?: boolean }
  const items: Item[] = [
    { label: 'React', value: 'react' },
    { label: 'Solid', value: 'solid' },
    { label: 'Vue', value: 'vue' },
    { label: 'Svelte', value: 'svelte', disabled: true },
  ]
  return (
    <Select.Root items={items} multiple>
      <Select.Label>Framework</Select.Label>
      <Select.Control>
        <Select.Trigger>
          <Select.ValueText placeholder="Select a Framework" />
          <Select.Indicator>
            <ChevronDownIcon />
          </Select.Indicator>
        </Select.Trigger>
        <Select.ClearTrigger>Clear</Select.ClearTrigger>
      </Select.Control>
      <Portal>
        <Select.Positioner>
          <Select.Content>
            <Select.ItemGroup>
              <Select.ItemGroupLabel>Frameworks</Select.ItemGroupLabel>
              {items.map((item) => (
                <Select.Item key={item.value} item={item}>
                  <Select.ItemText>{item.label}</Select.ItemText>
                  <Select.ItemIndicator>✓</Select.ItemIndicator>
                </Select.Item>
              ))}
            </Select.ItemGroup>
          </Select.Content>
        </Select.Positioner>
      </Portal>
      <Select.HiddenSelect />
    </Select.Root>
  )
}

Controlled Component

For scenarios where you want to control the Select component's state:

import { ChevronDownIcon } from 'lucide-react'
import { useState } from 'react'
import { Portal, Select } from '@ark-ui/react'

export const Controlled = () => {
  type Item = { label: string; value: string; disabled?: boolean }
  const [_, setSelectedItems] = useState<Item[]>([])

  const items: Item[] = [
    { label: 'React', value: 'react' },
    { label: 'Solid', value: 'solid' },
    { label: 'Vue', value: 'vue' },
    { label: 'Svelte', value: 'svelte', disabled: true },
  ]

  return (
    <Select.Root items={items} onValueChange={(e) => setSelectedItems(e.items)}>
      <Select.Label>Framework</Select.Label>
      <Select.Control>
        <Select.Trigger>
          <Select.ValueText placeholder="Select a Framework" />
          <Select.Indicator>
            <ChevronDownIcon />
          </Select.Indicator>
        </Select.Trigger>
        <Select.ClearTrigger>Clear</Select.ClearTrigger>
      </Select.Control>
      <Portal>
        <Select.Positioner>
          <Select.Content>
            <Select.ItemGroup>
              <Select.ItemGroupLabel>Frameworks</Select.ItemGroupLabel>
              {items.map((item) => (
                <Select.Item key={item.value} item={item}>
                  <Select.ItemText>{item.label}</Select.ItemText>
                  <Select.ItemIndicator>✓</Select.ItemIndicator>
                </Select.Item>
              ))}
            </Select.ItemGroup>
          </Select.Content>
        </Select.Positioner>
      </Portal>
      <Select.HiddenSelect />
    </Select.Root>
  )
}

Usage with a Form Library

See how to use the Select component with popular form libraries:

Example not found

TypeScript Caveats in Vue

Under the hood for React and Solid frameworks, we supply a complex prop type with a generic so that the type of the items prop matches the param type in the function signatures for props such as the isItemDisabled prop, say. (See the api reference table below) Unfortunately, generic typing is not supported in Vue for components that contain props with slots and/or emits. Therefore, you will not expect updated typing in this way.

If you have a solution or a workaround to this problem, we would love the contribution and request that you open a Github idea discussion to let us know a PoC you have to share!

API Reference

Root

PropDefaultType
items
T[] | readonly T[]

The options of the select

asChild
boolean

Render as a different element type.

closeOnSelect
boolean

Whether the select should close after an item is selected

defaultOpen
boolean

The initial open state of the select when it is first rendered. Use when you do not need to control its open state.

defaultValue
string[]

The initial value of the select when it is first rendered. Use when you do not need to control the state of the select.

disabled
boolean

Whether the select is disabled

form
string

The associate form of the underlying select.

highlightedValue
string

The key of the highlighted item

id
string

The unique identifier of the machine.

ids
Partial<{ root: string content: string control: string trigger: string clearTrigger: string label: string hiddenSelect: string positioner: string item(id: string | number): string itemGroup(id: string | number): string itemGroupLabel(id: string | number): string }>

The ids of the elements in the select. Useful for composition.

invalid
boolean

Whether the select is invalid

isItemDisabled
(item: T) => boolean

Whether the item is disabled

itemToString
(item: T) => string

The label of the item

itemToValue
(item: T) => string

The value of the item

lazyMountfalse
boolean

Whether to enable lazy mounting

loopFocus
boolean

Whether to loop the keyboard navigation through the options

multiple
boolean

Whether to allow multiple selection

name
string

The `name` attribute of the underlying select.

onExitComplete
() => void

Function called when the animation ends in the closed state.

onFocusOutside
(event: FocusOutsideEvent) => void

Function called when the focus is moved outside the component

onHighlightChange
(details: HighlightChangeDetails<T>) => void

The callback fired when the highlighted item changes.

onInteractOutside
(event: InteractOutsideEvent) => void

Function called when an interaction happens outside the component

onOpenChange
(details: OpenChangeDetails) => void

Function called when the popup is opened

onPointerDownOutside
(event: PointerDownOutsideEvent) => void

Function called when the pointer is pressed down outside the component

onValueChange
(details: ValueChangeDetails<T>) => void

The callback fired when the selected item changes.

open
boolean

Whether the select menu is open

positioning
PositioningOptions

The positioning options of the menu.

present
boolean

Whether the node is present (controlled by the user)

readOnly
boolean

Whether the select is read-only

scrollToIndexFn
(details: ScrollToIndexDetails) => void

Function to scroll to a specific index

unmountOnExitfalse
boolean

Whether to unmount on exit.

value
string[]

The keys of the selected items

ClearTrigger

PropDefaultType
asChild
boolean

Render as a different element type.

Content

PropDefaultType
asChild
boolean

Render as a different element type.

Control

PropDefaultType
asChild
boolean

Render as a different element type.

HiddenSelect

PropDefaultType
asChild
boolean

Render as a different element type.

Indicator

PropDefaultType
asChild
boolean

Render as a different element type.

ItemGroupLabel

PropDefaultType
asChild
boolean

Render as a different element type.

ItemGroup

PropDefaultType
asChild
boolean

Render as a different element type.

ItemIndicator

PropDefaultType
asChild
boolean

Render as a different element type.

Item

PropDefaultType
asChild
boolean

Render as a different element type.

item
any

ItemText

PropDefaultType
asChild
boolean

Render as a different element type.

Label

PropDefaultType
asChild
boolean

Render as a different element type.

Positioner

PropDefaultType
asChild
boolean

Render as a different element type.

Trigger

PropDefaultType
asChild
boolean

Render as a different element type.

ValueText

PropDefaultType
asChild
boolean

Render as a different element type.

placeholder
string

Text to display when no value is selected.