Select primitive
Headless Select: the behavior, keyboard support and ARIA of the WAI-ARIA Select-only combobox pattern, with no styles.
@ndop/primitives/select- WAI-ARIA: Select-only combobox
Import
Primitives ship in the @ndop/primitives package and have no styles. Their state is on data attributes for you to style. The styled Select is built on this one.
import {
NdSelect,
NdSelectGroup,
NdSelectItemText,
NdSelectLabel,
NdSelectSeparator,
NdSelectContent,
NdSelectItem,
NdSelectItemIndicator,
NdSelectTrigger,
NdSelectValue,
} from '@ndop/primitives/select';Accessibility
Implements the Select-only combobox pattern of the WAI-ARIA Authoring Practices.
Keyboard
Keys the component handles.
| Key | Action |
|---|---|
| EnterorSpace | On the trigger, opens the listbox; on an option, selects it, closes and focuses the trigger. |
| ArrowDownorArrowUp | On the trigger, opens the listbox; in it, moves to the next or previous enabled option. |
| HomeorEnd | In the listbox, moves to the first or last enabled option. |
| a | Typeahead: on the closed trigger, selects the next option starting with the typed letters; in the listbox, moves to it. |
| Escape | Closes the listbox and focuses the trigger. |
| Tab | Closes the listbox and moves focus on from the trigger. |
Focus
- Opening focuses the selected option, or the first enabled one.
- Selecting an option,
EscapeandTabclose the listbox; the first two return focus to the trigger. A click outside closes it where focus is. - Focus leaving the trigger and listbox marks a bound field touched.
Right-to-left
start and end alignments are logical and swap in right-to-left layouts. The listbox is vertical, so its arrow keys don't change.
API reference
NdSelect
[ndSelect]from @ndop/primitives/selectRoot of a select: the WAI-ARIA select-only combobox pattern, a button
that shows its value and opens a listbox of options. The listbox composes
the CDK's CdkListbox and is written in place; opening moves it into a
CDK overlay below the trigger. Put it on an ng-container, and bind
forms on the NdSelectTrigger.
The listbox is never shown on the server; an initial open state takes
effect after hydration.
| NdSelect binding | Type | Default |
|---|---|---|
[defaultValue]Initial value when it isn't bound. | string | null | null |
[defaultOpen]Initial open state when open isn't bound, applied after hydration. | boolean | false |
[disabled]Disables the trigger. A disabled bound field does too. | boolean | false |
[required]Marks the select required: aria-required="true" on the trigger. | boolean | false |
[invalid]Marks the select invalid when no forms library is bound; with one, the
field's state decides. | boolean | false |
[(value)]The selected option's value, or null when none is. Two-way bindable
with [(value)]. | string | null | null |
[(open)]Whether the listbox is open. Two-way bindable with [(open)]. | boolean | false |
NdSelectGroup
[ndSelectGroup]role groupfrom @ndop/primitives/selectGroups options (role="group"). Name it with aria-labelledby pointing
at a NdSelectLabel.
NdSelectItemText
[ndSelectItemText]from @ndop/primitives/selectThe text of an option, which the trigger shows while it's selected and typeahead matches. Without one, the option's own text is used.
NdSelectLabel
[ndSelectLabel]from @ndop/primitives/selectA heading for a group of options, as plain text; point the group's
aria-labelledby at it.
NdSelectSeparator
[ndSelectSeparator]from @ndop/primitives/selectA decorative line between groups of options, hidden from assistive technology: a listbox may contain only options and groups.
Manages aria-hidden.
NdSelectContent
[ndSelectContent]role listboxfrom @ndop/primitives/selectThe listbox of options (role="listbox"), composing CdkListbox. Write
it after the trigger: it has the hidden attribute while closed, and
opening moves it into an overlay below the trigger. It takes its name
from the trigger's labels, or its own aria-label.
Manages aria-labelledby, aria-label, aria-orientation, id, hidden.
| NdSelectContent binding | Type | Default |
|---|---|---|
[side]Side of the trigger it opens on, before flipping. | 'start' | 'end' | 'bottom' | 'top' | 'bottom' |
[align]Alignment along that side. | 'start' | 'end' | 'center' | 'start' |
[sideOffset]Gap between the trigger and the listbox, in pixels. | number | 4 |
| Data attribute | Values |
|---|---|
data-state | — |
data-side | — |
data-align | — |
NdSelectItem
[ndSelectItem]role optionfrom @ndop/primitives/selectOne option (role="option"), composing CdkOption. Clicking it, or
Enter or Space on it, selects it and closes the listbox.
Manages aria-selected, aria-disabled, id.
| NdSelectItem binding | Type | Default |
|---|---|---|
[value]requiredThe value the select takes when it's chosen. | string | — |
[disabled]Makes it unselectable; arrow keys skip it. | boolean | false |
[label]Its text, when it differs from what it renders. | string | null | null |
| Data attribute | Values |
|---|---|
data-state | — |
data-highlighted | — |
data-disabled | — |
NdSelectItemIndicator
[ndSelectItemIndicator]from @ndop/primitives/selectThe check of an option. It has the hidden attribute unless its option
is selected.
Manages hidden.
| Data attribute | Values |
|---|---|
data-state | — |
NdSelectTrigger
button[ndSelectTrigger]role comboboxfrom @ndop/primitives/selectThe button that shows the select's value and opens its listbox
(role="combobox"), on a native button. Name it with a
label[ndLabel] whose for is its id, or with aria-label. The
select owns its value, so this is a ControlValueAccessor: bind Signal
Forms ([formField]), reactive or template-driven forms here (ADR-0004,
amendments 1 and 4).
Manages aria-haspopup, aria-expanded, aria-controls, aria-required, aria-invalid, aria-describedby.
| Data attribute | Values |
|---|---|
data-state | — |
data-placeholder | — |
data-disabled | — |
data-invalid | — |
NdSelectValue
[ndSelectValue]from @ndop/primitives/selectThe selected option's text, or placeholder while none is selected. Put
it inside the trigger.
| NdSelectValue binding | Type | Default |
|---|---|---|
[placeholder]What it shows while no option is selected. | string | '' |
| Data attribute | Values |
|---|---|
data-placeholder | — |