Select
The form dropdown — a closed trigger showing the current value, a panel of options on click. Nearly always you want SimpleSelect: hand it an items array and it builds the whole thing. Reach for the compound parts only when an option row needs markup of its own, like a unit symbol or a status dot next to the label.
ts
import { Select, SelectTrigger, SelectContent, SelectItem, SelectValue, SimpleSelect } from '@scaler-tech/aurora/select'SimpleSelect
Collection frequency: monthly
Missing value
A required field left empty — missing colors the border and adds the marker icon.
Multiple
Emission scopes: scope-1
Popper
position="popper" drops the panel below the trigger at trigger width instead of overlaying it.
Custom option rows
Energy unit: —
Use when
| Situation | Use | Why |
|---|---|---|
| Pick one value in a form, options are plain labels | SimpleSelect | one array, no template |
| Same, but rows carry icons, tags, or secondary text | Select + parts | the row is your markup |
| The list is long enough that typing to narrow it matters, plain labels | SimpleCombobox | one array, search over the labels |
| Same, but rows need custom markup or grouping | Combobox + parts | text input plus filtering, the row is your markup |
| Filtering wanted, but not inside a form — a popover or sidebar list | Listbox | not a form element, no field chrome |
| Few options that should all stay visible | SegmentedControl | the options are the UI |
| A pill in the filter row above a table | FilterTrigger + FilterPanel | filter chrome, not field chrome |
API
SimpleSelect
Forwards every SelectRootProps prop and emit through to reka's SelectRoot, so v-model, multiple, defaultValue, by, name, and required all work. The ones you reach for:
| Prop | Type | Default | Description |
|---|---|---|---|
v-model | string | number | — | Selected value; matches an item's value — numeric ids stay numbers |
items | { value: string | number, label: string, disabled?: boolean }[] | — | Required, rendered in array order |
placeholder | string | '' | Trigger text while nothing is selected |
position | 'popper' | 'item-aligned' | 'item-aligned' | Passed to SelectContent; see the compound table below |
multiple | boolean | false | v-model becomes an array; the trigger joins labels with , |
| validation | FormStateProps | — | error / warning / success / missing / disabled / readonly booleans; the first four color the border and add an icon |
Its panel carries an inline z-index: 100000, which no class can lower — the compound form's z-9999 is what you drop to if a select ever has to sit under something.
Compound parts
| Component | Prop | Type | Default | Description |
|---|---|---|---|---|
Select | — | SelectRootProps & FormStateProps | — | State only; renders no element |
SelectTrigger | class | string | — | Merged over the field styling; where you put the width |
SelectValue | placeholder | string | '' | Shown until something is selected |
SelectContent | position | 'popper' | 'item-aligned' | 'item-aligned' | item-aligned overlays the trigger so the selected row lands where the trigger was (native macOS select); the panel sizes itself from reka's inline styles and shows scroll buttons when it overflows. popper drops the panel below the trigger at trigger width, like Combobox |
SelectContent | bodyLock | boolean | false | Aurora overrides reka's default; the page behind stays scrollable |
SelectItem | value | string | — | Required |
SelectItem | disabled | boolean | false | Dimmed, not selectable |
SelectItem | textValue | string | — | Overrides the scraped label used by the trigger and typeahead |
Example
vue
<SimpleSelect v-model="frequency" :items="frequencies" placeholder="Pick a frequency" />
<Select v-model="unit">
<SelectTrigger>
<SelectValue placeholder="Pick a unit" />
</SelectTrigger>
<SelectContent>
<SelectItem v-for="u in units" :key="u.value" :value="u.value" :text-value="u.label" class="pr-8">
{{ u.label }}
<span class="text-secondary ml-2">{{ u.symbol }}</span>
</SelectItem>
</SelectContent>
</Select>Incorrect / Correct
Incorrect (four compound parts to render plain labels — SimpleSelect is the same dropdown):
vue
<Select v-model="frequency">
<SelectTrigger>
<SelectValue :placeholder="translate('automations.select-frequency')" />
</SelectTrigger>
<SelectContent>
<SelectItem v-for="f in frequencies" :key="f.value" :value="f.value">
{{ f.label }}
</SelectItem>
</SelectContent>
</Select>Correct (the wrapper renders exactly that tree, and keeps the panel above modals):
vue
<SimpleSelect
v-model="frequency"
:items="frequencies"
:placeholder="translate('automations.select-frequency')"
/>Gotchas
- A
classonSimpleSelectorSelectis silently dropped, soclass="w-24"leaves a full-width dropdown — put the width on a wrapperdiv, or onSelectTrigger. - Validation props survive that same hop only because
Selectmerges them onto its first non-comment child — wrap the trigger in adivanderrorstops arriving. - Markup inside
SelectItemis flattened into the trigger label, so a muted "kWh" hint reappears asKilowatt hours kWhwhen closed — passtext-valuewith the clean label, andpr-8on the item so long labels clear the selected row's checkmark.[external] - Content inside
<SelectValue>pins that content: the selected label never renders and the placeholder never shows. Leave it empty unless you want a fixed trigger label.
Related
- Combobox — the same picker with a filter input, for long lists;
SimpleComboboxis the one-line form - Listbox — a filterable list outside form chrome
- Segmented control — few options, all visible at once
- Filter — pill triggers and panels for the filter row above a table