Select
Select lets a user pick from a short, known list of options.
Components · Form
Select lets a user pick one or more values from a fixed list. Because no browser lets you restyle a native <select>, Namirial select is built as a custom combobox: an .nm-input--select trigger paired with an .nm-dropdown menu, sharing every label, help-text, size, and validation token with input.
Overview
The Select component lets users choose one or more values from a predefined list of options. It provides a controlled way to capture structured input by limiting selections to values that have already been defined.
When to use
Use the Select component when:
- Users need to choose from a fixed set of mutually exclusive options, such as a country, language, document type, or currency.
- The number of options is too large for radio buttons but still manageable as a list (typically around 5–50 options).
- Users need to select multiple items from a predefined set, such as tags, roles, or categories (using a multi-select variant).
Anatomy
Select reuses the input's label, container, and help text unchanged. What's different is the container's content — a .nm-input__select-value instead of a text field — and a .nm-dropdown menu that opens beneath it.
Tokens and values that drive each part
| Part | Role | Source |
|---|---|---|
| Trigger | Same as input container | --nm-input-* (see Input) |
| Selected value | Text color | --nm-input-text |
| Placeholder | Text color | --nm-input-placeholder |
| Chevron | Rotation on open | .is-open .nm-input__icon-trailing { transform: rotate(180deg) } |
| Menu | Fill | --nm-dropdown-bg |
| Menu | Border / shadow | --nm-dropdown-border / --nm-dropdown-shadow |
| Option | Text color | --nm-dropdown-item-text |
| Option | Hover fill | --nm-dropdown-item-hover-bg |
| Option | Selected fill / marker | --nm-dropdown-item-active-bg / --nm-dropdown-item-active-fg |
Sizes
Select shares input's five-size scale — xs–xl — since the trigger is a .nm-input--select container underneath.
Multi-select
When more than one value can be chosen, render each selection as an .nm-tag inside the trigger instead of plain text, and mark matching menu items with .nm-dropdown__item--multi (a checkbox-style marker instead of the single-select dot).
Use .nm-input__container--flush-start so the first tag sits flush with the container's edge, matching the padding rhythm of a plain text value.
States
Select shares every interaction and validation state with input — hover, focus, read-only, error, warning, success — plus an open/closed state of its own.
Closed → hover → open (focused) → read-only
Error — same nm-input--error modifier as input
Light & dark theme
Both previews are locked — they don't follow the page theme switcher.
Do & don't
Accessibility
Namirial select follows the ARIA combobox pattern — it is not a native <select>, so all keyboard and screen-reader behavior must be wired explicitly.
Semantics
- Trigger:
role="combobox",aria-expanded,aria-controlspointing at the menu'sid,aria-haspopup="listbox". - Menu:
role="listbox"(orrole="listbox" aria-multiselectable="true"for multi-select), each optionrole="option"witharia-selected. - Keep a hidden native
<select>or a hidden<input>in sync with the chosen value so the field still submits inside a plain HTML<form>.
Keyboard
- Enter or Space on the trigger opens the menu; Escape closes it and returns focus to the trigger.
- Arrow Up / Down moves through options without closing the menu; Enter commits the highlighted option.
- Type-ahead: typing a letter jumps to the next option starting with it.
Labeling
- The trigger needs the same label association as input —
for/idor nesting. - Disabled options use
aria-disabled="true"andnm-dropdown__item--disabled; they stay in the DOM and are announced, just not selectable.
Playground
Token reference
Select inherits every --nm-input-* token from Input for its trigger. The menu has its own group:
| Token | Role |
|---|---|
| --nm-dropdown-bg | Menu fill |
| --nm-dropdown-border | Menu border |
| --nm-dropdown-shadow | Menu drop shadow |
| --nm-dropdown-item-text | Option text color |
| --nm-dropdown-item-hover-bg | Option fill on hover |
| --nm-dropdown-item-active-bg | Selected option fill |
| --nm-dropdown-item-active-fg | Selected option text / marker color |
| --nm-dropdown-separator | Divider line color |
| --nm-tag-bg / --nm-tag-fg / --nm-tag-border | Multi-select chip appearance |
Implementation
Select needs a small amount of JavaScript to toggle the menu and sync the chosen value — there is no native element to lean on.
<link rel="stylesheet" href="namirial-theme.css">
<div class="nm-input nm-input--select nm-input--md">
<label class="nm-input__label" id="country-label">Country</label>
<div class="nm-input__container" role="combobox"
aria-haspopup="listbox" aria-expanded="false"
aria-controls="country-listbox" aria-labelledby="country-label" tabindex="0">
<span class="nm-input__select-value--placeholder">Select a country</span>
<span class="nm-input__icon-trailing"><!-- chevron icon --></span>
</div>
<ul class="nm-dropdown" role="listbox" id="country-listbox" hidden>
<li class="nm-dropdown__item" role="option">Italy</li>
<li class="nm-dropdown__item" role="option">Germany</li>
</ul>
</div>CSS classes
| Class | Values | Default |
|---|---|---|
nm-input--select | Enables select cursor + chevron rotation | — |
is-open | Rotates the trailing chevron 180° | — |
nm-input__select-value / nm-input__select-value--placeholder | Selected text vs. empty state | — |
nm-dropdown__item--multi | Checkbox-style marker for multi-select | — |
nm-dropdown__item--disabled | Non-selectable option | — |
nm-dropdown__separator | Divider between groups of options | — |