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 { Portal, Select } from '@ark-ui/react'
import { ChevronDownIcon } from 'lucide-react'

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 id="framework">
              <Select.ItemGroupLabel htmlFor="framework">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.Root>
  )
}

Advanced Customization

For advanced customizations and item properties like disabled:

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

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 id="framework">
              <Select.ItemGroupLabel htmlFor="framework">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.Root>
  )
}

Multiple Selection

To enable multiple item selection:

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

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 id="framework">
              <Select.ItemGroupLabel htmlFor="framework">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.Root>
  )
}

Controlled Component

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

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

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 id="framework">
              <Select.ItemGroupLabel htmlFor="framework">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.Root>
  )
}

Usage with a Form Library

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

import { Select } from '@ark-ui/react'
import { ChevronsDownUpIcon } from 'lucide-react'
import { Controller, useForm, type SubmitHandler } from 'react-hook-form'

const FormLibrary = () => {
  type Inputs = {
    framework: string
  }
  const items = ['React', 'Solid', 'Vue']
  const { control, handleSubmit } = useForm<Inputs>()

  const onSubmit: SubmitHandler<Inputs> = (data) => console.log(data)

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <Controller
        name="framework"
        control={control}
        render={({ field }) => (
          <Select.Root onValueChange={(e) => field.onChange(e?.value)} items={items}>
            <Select.Label>Framework</Select.Label>
            <Select.Control>
              <Select.Trigger>
                <Select.ValueText placeholder="Select a Framework" />
                <Select.Indicator>
                  <ChevronsDownUpIcon />
                </Select.Indicator>
              </Select.Trigger>
              <Select.ClearTrigger>Clear</Select.ClearTrigger>
            </Select.Control>
            <Select.Positioner>
              <Select.Content>
                <Select.ItemGroup id="framework">
                  <Select.ItemGroupLabel htmlFor="framework">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>
          </Select.Root>
        )}
      />
      <button type="submit">Submit</button>
    </form>
  )
}

API Reference

Root

PropTypeDefault
items
T[] | readonly T[]
asChild
boolean
closeOnSelect
boolean
defaultValue
string[]
dir
'ltr' | 'rtl'"ltr"
disabled
boolean
form
string
getRootNode
() => Node | ShadowRoot | Document
highlightedValue
string
id
string
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 }>
invalid
boolean
isItemDisabled
(item: T) => boolean
itemToString
(item: T) => string
itemToValue
(item: T) => string
lazyMount
booleanfalse
loop
boolean
multiple
boolean
name
string
onExitComplete
() => void
onFocusOutside
(event: FocusOutsideEvent) => void
onHighlightChange
(details: HighlightChangeDetails<T>) => void
onInteractOutside
(event: InteractOutsideEvent) => void
onOpenChange
(details: OpenChangeDetails) => void
onPointerDownOutside
(event: PointerDownOutsideEvent) => void
onValueChange
(details: ValueChangeDetails<T>) => void
open
boolean
positioning
PositioningOptions
present
boolean
readOnly
boolean
selectOnBlur
boolean
unmountOnExit
booleanfalse
value
string[]

Item

PropTypeDefault
asChild
boolean
item
any

Label

PropTypeDefault
asChild
boolean

Content

PropTypeDefault
asChild
boolean

Control

PropTypeDefault
asChild
boolean

Trigger

PropTypeDefault
asChild
boolean

ItemText

PropTypeDefault
asChild
boolean

Indicator

PropTypeDefault
asChild
boolean

ItemGroup

PropTypeDefault
id
string
asChild
boolean

ValueText

PropTypeDefault
asChild
boolean

Positioner

PropTypeDefault
asChild
boolean

ClearTrigger

PropTypeDefault
asChild
boolean

ItemIndicator

PropTypeDefault
asChild
boolean

ItemGroupLabel

PropTypeDefault
htmlFor
string
asChild
boolean