Native select
Native select — the browser’s <select>, styled as far as CSS reaches: the box is Select’s trigger (Input’s chrome — 36px, radius 8, padding 8/12, 14px Regular, 1px border, elevation/flat — with the 16px chevron-down in text/muted), the list that opens is the browser’s and cannot be styled.
Beta · Forms · packages/css/src/components/native-select.css · React on Base UI: @pepperui/native-select
.pui-native-select wraps a real <select>; the chevron is a mask in text/muted. Never on a product screen.
Sizes across, states down.
What it is for
Section titled “What it is for”- Placeholder and Value — a placeholder is the disabled first option, selected until the user chooses
- No prefix, no leading icon: a native control cannot host them (Select can)
- Three sizes and five states, Select’s exactly — the box is the same component drawn twice so a form can be re-platformed without a visual change
- Never used in a product screen — product screens take Select
- Filled true — the box on surface/card instead of white, so a form on a white page can tell its dropdowns from its inputs: The design lead’s call on the site’s blog and careers filters, ‘for visibility’ (request 19)
Use when a form must work without JavaScript — a server-rendered admin page, a form embedded where scripts do not run, an email-safe page.
Do not use when the page runs the design system’s JavaScript (that is Select); the list needs search or typing (Combobox); the options are few enough to show (Radio); on any deck-tool or MAFO screen.
Relates to Select, Field, Combobox, Input, Radio.
Anti-patterns styling the open list (it cannot be — say so in the review, do not mock it) · a native select in a product screen · a placeholder that is not the disabled first option · the browser’s own arrow flush at the edge · a fill changed on the instance.
Keywords: native select, select, form, no-js, dropdown, browser
Figma — page Select: Native select (30 variants)
shadcn: native-select
The markup — copy this
Section titled “The markup — copy this”The class, the parts, and nothing that is not in the package. The same block opens native-select.css.
<span class="pui-native-select"><select aria-label="Category"><option value="" disabled selected>Choose…</option>…</select></span>The modifiers
Section titled “The modifiers”| What it is | Note | |
|---|---|---|
| Size | --small · (none) medium · --large — on the wrapper, mirroring Select | — |
| State | the select’s own: :hover · :focus · [aria-invalid=“true”] (+ the error ring when focused) · :disabled | — |
Accessibility — measured, not assumed
Section titled “Accessibility — measured, not assumed”Every number here is measured on the rendered component: contrast (npm run contrast:render), the focus ring (npm run focus) and the keyboard (npm run keyboard). The floors are principle 12’s.
Contrast
Section titled “Contrast”| ink on ground | reads | floor | the matrix calls it | |
|---|---|---|---|---|
#544d4d on #ffffff |
8.24 | 4.5 | text.muted on surface.page (promised) | ok |
#0b0202 on #ffffff |
20.51 | 4.5 | text.default on surface.page (promised) | ok |
2 distinct pair(s) rendered, 0 that axe calls a violation.
The focus ring
Section titled “The focus ring”| primitive | on | the indicator | over | the change | |
|---|---|---|---|---|---|
| Native select | surface/page | shadow #6a66e4 2 px |
#ffffff |
4.53 | ok |
| Native select | surface/card | shadow #6a66e4 2 px |
#f2f2f7 |
4.06 | ok |
| Native select | surface/sunken | shadow #6a66e4 2 px |
#f2f2f2 |
4.05 | ok |
3 of 3 focus stop(s) in this block meet WCAG 2.4.13 on screen — the same crop screenshotted focused and unfocused, and the difference measured.
Keyboard
Section titled “Keyboard”Nothing in this component claims an ARIA role with a keyboard contract; its controls are ordinary ones and the browser already gives them their keys.
Tab order across the whole library is document order over 344 stops, and Shift+Tab is its exact reverse — no keyboard trap anywhere (WCAG 2.1.2).
Pepper UI v1.5.0
The Mobupps design system. 386 tokens, 88 components, 65 pages in the workshop — every page of this site generated from the repository, so nothing here is typed twice.