Skip to content
Highlight

ComponentsUpdated Sep 9, 2026

Select

A single-choice picker. Pass items to the root so the trigger can show the selected label and size itself to the widest option.

Import

Source: packages/ui/src/components/select

tsx
import { Select, SelectItemType } from '@highlight/ui'
Model
tsx
import { Select, type SelectItemType } from '@highlight/ui'

const MODELS: Array<SelectItemType> = [
  { label: 'Claude Fable 5.1', value: 'fable' },
  { label: 'Claude Opus 5', value: 'opus' },
  { label: 'Claude Sonnet 5', value: 'sonnet' },
  { label: 'Claude Haiku 4.5', value: 'haiku' },
]

export default function SelectBasic() {
  return (
    <Select items={MODELS} defaultValue="fable">
      <Select.Label>Model</Select.Label>
      <Select.Trigger />
      <Select.Content>
        {MODELS.map((item) => (
          <Select.Item key={String(item.value)} value={item.value}>
            {item.label}
          </Select.Item>
        ))}
      </Select.Content>
    </Select>
  )
}

Trigger sizes

default, compact, and badge. With a placeholder, badge collapses to plain text until a value is chosen.

tsx
import { Select, type SelectItemType } from '@highlight/ui'

const STATUSES: Array<SelectItemType> = [
  { label: 'Todo', value: 'todo' },
  { label: 'In progress', value: 'in-progress' },
  { label: 'Done', value: 'done' },
]

function StatusItems() {
  return (
    <Select.Content>
      {STATUSES.map((item) => (
        <Select.Item key={String(item.value)} value={item.value}>
          {item.label}
        </Select.Item>
      ))}
    </Select.Content>
  )
}

export default function SelectSizes() {
  return (
    <div className="flex flex-wrap items-end justify-center gap-4">
      <Select items={STATUSES} defaultValue="todo">
        <Select.Trigger />
        <StatusItems />
      </Select>
      <Select items={STATUSES} defaultValue="in-progress">
        <Select.Trigger size="compact" />
        <StatusItems />
      </Select>
      <Select items={STATUSES} defaultValue="done">
        <Select.Trigger size="badge" />
        <StatusItems />
      </Select>
      <Select items={STATUSES}>
        <Select.Trigger size="badge" placeholder="+ Status" />
        <StatusItems />
      </Select>
    </div>
  )
}
Visibility

Selected: team

tsx
import { useState } from 'react'
import { Globe, Lock, Users } from 'lucide-react'
import { Select, type SelectItemType } from '@highlight/ui'

const VISIBILITY: Array<SelectItemType> = [
  { label: 'Private', value: 'private', icon: <Lock /> },
  { label: 'Team', value: 'team', icon: <Users /> },
  { label: 'Anyone with the link', value: 'public', icon: <Globe /> },
]

export default function SelectIcons() {
  const [value, setValue] = useState<string | null>('team')

  return (
    <div className="flex flex-col items-start gap-2">
      <Select items={VISIBILITY} value={value} onValueChange={(next) => setValue(next as string | null)}>
        <Select.Label>Visibility</Select.Label>
        <Select.Trigger placeholder="Choose…" />
        <Select.Content>
          {VISIBILITY.map((item) => (
            <Select.Item key={String(item.value)} value={item.value} icon={item.icon}>
              {item.label}
            </Select.Item>
          ))}
        </Select.Content>
      </Select>
      <p className="text-foreground/60 text-xs">Selected: {value ?? 'none'}</p>
    </div>
  )
}

Parts

Compound sub-components. Every part accepts className and forwards the rest of its props to Base UI.

Select.Label
Text above the trigger.
Select.Trigger
size: 'default' | 'compact' | 'badge'; placeholder; hideIcon; minWidth.
Select.Content
Portal + Positioner + Popup with scroll arrows. showScrollArrows, positionerProps.
Select.Item
value, icon, onClick.
Select.Value / Icon
Base UI parts for custom triggers.

Props

Props added on top of the underlying element or Base UI part.

PropTypeDefaultDescription
itemsArray<SelectItemType>label, value, optional icon. Drives the trigger label and width.
autoWidthbooleantrueSize the trigger to the widest label.
minWidthstringExplicit trigger min-width; disables autoWidth.