Basic Input
A labelled text input with helper text wired to it via aria-describedby.
6 frameworksBeginner
A styled native `<select>` - the accessible baseline, with the platform popup left intact.
<!--
A real <select>. That is the entire component, and that is the point: the
browser supplies keyboard navigation, type-ahead, the platform popup and the
mobile wheel, and none of it can drift out of sync with a hand-rolled listbox.
Only the box is restyled - the popup list is the OS's and stays that way.
Reach for a custom listbox when an option row needs markup <option> cannot
hold, or when more than one value can be chosen. Never reach for one because
the arrow is the wrong grey.
-->
<div class="nsel">
<label class="nsel__label" for="nsel-plan">Plan</label>
<div class="nsel__control">
<select class="nsel__select" id="nsel-plan" name="plan">
<option value="starter">Starter</option>
<option value="growth">Growth</option>
<option value="scale">Scale</option>
<option value="enterprise">Enterprise</option>
</select>
<svg class="nsel__chevron" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false">
<path d="m6 9 6 6 6-6" />
</svg>
</div>
</div>| Prop | Type | Default | Description |
|---|---|---|---|
labelrequired | string | - | Accessible label announced while loading. |
itemsrequired | SelectItem[] | - | The array of items to render. |
value | string | - | The metric's current value, pre-formatted. |
onSelect | (value: string) => void | - | Fired with the menu item the user chose. |
disabled | boolean | false | Prevents interaction and dims the control. |
className | string | - | Additional classes merged onto the root element. |
The only thing restyled is the box: `appearance-none` drops the OS arrow so the chevron can take its place, and everything inside the popup stays the browser’s. That is the trade being made, and it is a good one - you get keyboard navigation, type-ahead and the iOS wheel for free, and none of it can rot. `color-scheme` is the one lever CSS has over the popup itself; without it the option list paints light on a dark page. Reach for `select-custom` when an option row needs markup `<option>` cannot hold - never because the arrow is the wrong grey.