Form

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.

Select a type
Passport
National ID
Driver's licence

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

PartRoleSource
TriggerSame as input container--nm-input-* (see Input)
Selected valueText color--nm-input-text
PlaceholderText color--nm-input-placeholder
ChevronRotation on open.is-open .nm-input__icon-trailing { transform: rotate(180deg) }
MenuFill--nm-dropdown-bg
MenuBorder / shadow--nm-dropdown-border / --nm-dropdown-shadow
OptionText color--nm-dropdown-item-text
OptionHover fill--nm-dropdown-item-hover-bg
OptionSelected 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.

xs
Placeholder
12px · h 24px · r 6
sm
Placeholder
14px · h 32px · r 8
md
Placeholder
16px · h 40px · r 10
lg
Placeholder
20px · h 48px · r 12
xl
Placeholder
24px · h 56px · r 12

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).

SignerApprover

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.

Select
Select
Italy

Closed → hover → open (focused) → read-only

Select a country
Select a country to continue.

Error — same nm-input--error modifier as input

Light & dark theme

Light data-theme="light"
Italy
Italy
Germany
Dark data-theme="dark"
Italy
Italy
Germany

Both previews are locked — they don't follow the page theme switcher.

Do & don't

✓Do
Select currency
Use a placeholder that names what's being chosen, not a generic "Select".
✕Don't
USD
Don't pre-select a value the user hasn't actually chosen — an empty placeholder is more honest than a silent default.
✓Do
For 2–4 always-visible options, use radio — it's faster than opening a menu.
✕Don't
Sign
Don't hide two or three options behind a click when they could all be visible at once.

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-controls pointing at the menu's id, aria-haspopup="listbox".
  • Menu: role="listbox" (or role="listbox" aria-multiselectable="true" for multi-select), each option role="option" with aria-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/id or nesting.
  • Disabled options use aria-disabled="true" and nm-dropdown__item--disabled; they stay in the DOM and are announced, just not selectable.

Playground

<div class="nm-input nm-input--select nm-input--md"> <label class="nm-input__label">Country</label> <div class="nm-input__container" role="combobox" aria-expanded="false"> <span class="nm-input__select-value">Italy</span> <span class="nm-input__icon-trailing"></span> </div> </div>

Token reference

Select inherits every --nm-input-* token from Input for its trigger. The menu has its own group:

TokenRole
--nm-dropdown-bgMenu fill
--nm-dropdown-borderMenu border
--nm-dropdown-shadowMenu drop shadow
--nm-dropdown-item-textOption text color
--nm-dropdown-item-hover-bgOption fill on hover
--nm-dropdown-item-active-bgSelected option fill
--nm-dropdown-item-active-fgSelected option text / marker color
--nm-dropdown-separatorDivider line color
--nm-tag-bg / --nm-tag-fg / --nm-tag-borderMulti-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

ClassValuesDefault
nm-input--selectEnables select cursor + chevron rotation—
is-openRotates the trailing chevron 180°—
nm-input__select-value / nm-input__select-value--placeholderSelected text vs. empty state—
nm-dropdown__item--multiCheckbox-style marker for multi-select—
nm-dropdown__item--disabledNon-selectable option—
nm-dropdown__separatorDivider between groups of options—