Select
18 partsA custom, fully stylable replacement for the native <select> element: a
trigger button that opens a floating listbox of options, with full keyboard
support (arrow keys, Home/End, type-ahead search), focus trapping, and an
optional hidden native <select> for native form submission.
Use it when you need a single- or multi-choice dropdown whose menu and options
must be styled beyond what a native control allows. The root owns the selected
value and open state and provides context to every part; bind v-model for
the value and v-model:open (or listen to update:modelValue / update:open)
to control or observe it. Values may be strings, numbers, booleans, or objects
(compared via by). Compose it from a SelectTrigger (with
SelectValue/SelectIcon) plus a portalled SelectContent of SelectItems.
Demo
Anatomy
Import the parts and compose them. Each part forwards attributes to its underlying element.
import {
SelectRoot,
SelectTrigger,
SelectValue,
SelectIcon,
SelectPortal,
SelectContent,
SelectViewport,
SelectScrollUpButton,
SelectScrollDownButton,
SelectGroup,
SelectLabel,
SelectItem,
SelectItemText,
SelectItemIndicator,
SelectSeparator,
SelectArrow,
SelectProvider,
SelectBubbleSelect,
} from '@robonen/primitives/selection/select';
<SelectRoot>
<SelectTrigger />
<SelectValue />
<SelectIcon />
<SelectPortal />
<SelectContent />
<SelectViewport />
<SelectScrollUpButton />
<SelectScrollDownButton />
<SelectGroup />
<SelectLabel />
<SelectItem />
<SelectItemText />
<SelectItemIndicator />
<SelectSeparator />
<SelectArrow />
<SelectProvider />
<SelectBubbleSelect />
</SelectRoot>API Reference
SelectRoot
RootA custom, fully stylable replacement for the native `<select>` element: a trigger button that opens a floating listbox of options, with full keyboard support (arrow keys, Home/End, type-ahead search), focus trapping, and an optional hidden native `<select>` for native form submission. Use it when you need a single- or multi-choice dropdown whose menu and options must be styled beyond what a native control allows. The root owns the selected value and open state and provides context to every part; bind `v-model` for the value and `v-model:open` (or listen to `update:modelValue` / `update:open`) to control or observe it. Values may be strings, numbers, booleans, or objects (compared via `by`). Compose it from a `SelectTrigger` (with `SelectValue`/`SelectIcon`) plus a portalled `SelectContent` of `SelectItem`s.
| Prop | Type | Description |
|---|---|---|
modelValue? | SelectModelValue<T, Multiple> | Controlled value. Bind with v-model. |
dir? | Direction | Reading direction. Falls back to ConfigProvider. |
disabled? | boolean | Disable the whole select. |
required? | boolean | Mark field as required for native form validation. |
name? | string | Native input name for form submission. |
defaultValue? | SelectModelValue<T, Multiple> | Uncontrolled default value. |
defaultOpen? | boolean | Uncontrolled default open state. |
multiple? | Multiple | Allow selecting multiple options; the model becomes an array. |
by? | string | ((a: T, b: T) => boolean) | Compare object values by a property key or a custom comparator. Omitted →
=== for primitives / structural deep-equality for objects. |
autocomplete? | string | Native autocomplete attribute forwarded to the hidden native select. |
open? | boolean | Two-way bound value (v-model:open). |
| Event | Payload |
|---|---|
update:open | [value: boolean] |
SelectTrigger
TriggerThe button that toggles the select open and anchors the floating content. Renders as a `role="combobox"` control wired with the appropriate ARIA and `data-state`/`data-placeholder` attributes; place a `SelectValue` and `SelectIcon` inside it. Supports type-to-select while closed and touch-device pointer hardening.
| Prop | Type | Description |
|---|---|---|
disabled? | boolean | Disable this trigger independently from the root. |
SelectValue
ValueDisplays the label(s) of the currently selected option(s) inside the trigger, or the `placeholder` when nothing is selected. Renders into a non-interactive span so pointer events fall through to the trigger. Exposes the resolved `selectedLabel` array and raw `modelValue` to its default slot for custom rendering (e.g. multi-value chips), and reflects a `data-placeholder` attribute while empty.
| Prop | Type | Description |
|---|---|---|
placeholder? | string | Text shown when no option is selected. |
SelectIcon
IconThe decorative icon shown in the trigger (a chevron by default). Marked `aria-hidden`; override the default glyph by passing slot content.
No props or events — renders its element and forwards attributes.
SelectPortal
PortalTeleports the `SelectContent` into a different part of the DOM (the document body by default) so it escapes overflow and stacking-context clipping.
No props or events — renders its element and forwards attributes.
SelectContent
ContentThe floating panel that holds the options. While open it mounts `SelectContentImpl` behind `Presence` (so it can animate in and out); while closed it still renders the options into a detached `DocumentFragment` so each `SelectItem` registers its value/label and `SelectValue` shows the initially-selected label before the dropdown is ever opened. Usually placed inside a `SelectPortal` and contains a `SelectViewport` of `SelectItem`s.
| Prop | Type | Description |
|---|---|---|
forceMount? | boolean | Force mounting (keeps the panel in the DOM) for externally-controlled animation libraries. |
SelectViewport
ViewportThe scrollable region inside the content that wraps the options. Marked `role="presentation"` (the listbox role lives on the content element), caps its height to the available space, and scrolls when the list overflows. In `item-aligned` mode it grows the panel as you scroll (MacOS-style). Pair it with the scroll buttons for an item-aligned menu.
| Prop | Type | Description |
|---|---|---|
nonce? | string | CSP nonce for the injected scrollbar-hiding <style> tag. Falls back to
the active ConfigProvider nonce. |
SelectGroup
GroupGroups a set of related items under a shared label. Renders as a `role="group"` and provides an id so a child `SelectLabel` can label the group for assistive technology.
No props or events — renders its element and forwards attributes.
SelectLabel
LabelA non-selectable heading for a `SelectGroup`. Renders the text that labels the group and wires its id to the group's `aria-labelledby`; must be used inside a `SelectGroup`.
No props or events — renders its element and forwards attributes.
SelectItem
ItemA single selectable option. Renders as a `role="option"`, registers its value and text with the root, becomes (or toggles, when `multiple`) the selected value on click/Enter/Space, and exposes `data-state`/`data-disabled`/ `data-highlighted` for styling. Holds a `SelectItemText` and, optionally, a `SelectItemIndicator`. The value may be any {@link AcceptableValue}.
| Prop | Type | Description |
|---|---|---|
value | T | The option value. Must not be an empty string. |
disabled? | boolean | Disable this item. |
textValue? | string | Optional text used for typeahead. Defaults to the SelectItemText content;
set it when the item content is complex or non-textual. |
SelectItemText
ItemTextThe visible label of a `SelectItem`. Its text is what the root captures to show in `SelectValue` once the item is chosen, so each item should contain exactly one; use inside a `SelectItem`.
No props or events — renders its element and forwards attributes.
SelectItemIndicator
ItemIndicatorA marker (typically a checkmark) rendered only while its `SelectItem` is the selected option. Decorative and `aria-hidden`; use inside a `SelectItem`.
No props or events — renders its element and forwards attributes.
SelectSeparator
SeparatorA visual divider between groups or items in the content. Renders as a horizontal `role="separator"` and is purely decorative.
No props or events — renders its element and forwards attributes.
SelectArrow
ArrowNo props or events — renders its element and forwards attributes.
SelectProvider
ProviderRe-provides the root context and a no-op content context so that `SelectItem`/`SelectItemText` can mount inside a detached `DocumentFragment` while the listbox is closed. This lets every option register its value and label up-front, so `SelectValue` shows the initially-selected label before the dropdown is ever opened. Internal — rendered by `SelectContent`.
| Prop | Type | Description |
|---|---|---|
context | SelectRootContext | — |
SelectBubbleSelect
BubbleSelectA real, visually-hidden native `<select>` mirrored from the custom control so the value participates in native form submission, autofill, and `change` bubbling. Renders an `<option>` per registered item, supports `multiple`, and writes through the native value setter so frameworks that observe form controls (and the browser's autofill) see the change exactly as for a real `<select>`. Internal — rendered by `SelectRoot` when a `name` is set inside a form.
| Prop | Type | Description |
|---|---|---|
autocomplete? | string | — |
disabled? | boolean | — |
multiple? | boolean | — |
name? | string | — |
required? | boolean | — |
options | AcceptableValue[] | Registered option values, rendered as native <option>s. |
value? | AcceptableValue | AcceptableValue[] | Current model value(s). |
| Event | Payload |
|---|---|
change | [value: string] |