Component
StableForm

Select

Dropdown select fields for choosing from a predefined list of options. Uses the same .input class as all form fields — identical styling, focus ring, and validation states.

Overview

Select uses the native <select> element with the .input class applied. This ensures visual consistency with text inputs and textareas. Always include a blank default option with a descriptive placeholder like "Select role..." when no default is pre-selected.

Variants

All States
Filter by regional assignment.
Please select a status.

Filter Bar Select

In filter bars, selects are used without labels, inside a flex row. They use the same .input class with flex:1; min-width:160px.

AI Implementation Notes

For AI coding assistants: Select uses the native HTML <select> element with the .input class — no custom dropdown component needed. Always include an empty first option for unselected state: <option value="">Select...</option>. Error state: add .input-error to the select AND render .form-error-msg below. In filter bars, omit the label and use flex:1; min-width:160px.

When to Use

Use Select when
  • Choosing one option from 4–15 predefined choices
  • Filter bars (role, status, region)
  • Form fields with enumerated values
Don't use Select when
  • Only 2–3 options — use radio buttons or a button group
  • User can type a custom value — use a combobox
  • More than 15 options — use searchable select

Properties

PropertyTypeRequiredDefaultDescription
optionsarrayrequiredArray of option objects or strings: {value, label}. Always include a blank first option as placeholder: {value:'', label:'Select...'}.
valuestringoptional''Currently selected value.
errorstringoptionalundefinedError message. Adds .input-error to select and .form-error-msg below.
disabledbooleanoptionalfalseDisabled state. Same visual treatment as input.

Design Decisions

Why use native select instead of a custom dropdown component?
Native select elements have built-in accessibility (keyboard navigation, screen reader support), work on all devices including touch, and require zero JavaScript. Custom dropdowns require significant effort to match this accessibility baseline. For simple list selection, native select is the correct choice. Complex cases (multi-select, searchable, grouped) would warrant a custom component.

Changelog

v1.0.0July 2026Added
  • Native select with .input class — consistent with input/textarea styling
  • Filter bar usage pattern documented
Default
border:#E2E8F0, placeholder shown
Focus
border:#3B5BDB + 3px ring
Required
Error
border:#F05252 + error msg
Disabled
bg:#F8FAFC, cursor:not-allowed

Accessibility

RequirementImplementation
labelAlways link label via for/id. Label class: .form-label. Never use placeholder as label substitute.
aria-requiredAdd aria-required="true" for required fields.
aria-invalidAdd aria-invalid="true" when in error state.
Native selectUse native <select> — has built-in keyboard navigation, screen reader support, touch support.

Composition

Allowed
Inside .form-group with .form-label
Filter bar without label (flex:1 min-width:160px)
Modal form fields
Forbidden
Without a label or aria-label
More than 15 options without grouping
As navigation trigger — use Dropdown instead

Best Practices

Do
Always include a blank first option as placeholder: <option value="">Select...</option>
Users need a clear unselected state — especially for required fields.
Don't
Pre-select the first real option by default when no selection is valid yet.
Pre-selecting hides the fact that no choice has been made, causing silent form submission errors.

Anatomy

1
Label
label.form-label. UPPERCASE 12px fw-700 letter-spacing:.5px. Always linked via for/id. Never omitted.
2
Select Element
Native <select class="input">. Same styling as text input. cursor:pointer, appearance:auto (native dropdown arrow retained).
3
Options
First option always value="" as placeholder. Remaining options as <option value="key">Label</option>.
4
Validation Message
div.form-error-msg when invalid. Same pattern as input error states.

Content Rules

Select role...
Clear, lowercase, with ellipsis indicating selection needed
--Choose--
Dashes are visual noise. Use natural language.

States

Default
border:#E2E8F0, placeholder visible
Focus
border:#3B5BDB + 3px ring
Error
border:#F05252 + error msg below
Disabled
bg:#F8FAFC, cursor:not-allowed

Behavior

TriggerBehavior
Click / FocusOpens native browser dropdown. border-color:#3B5BDB + box-shadow focus ring applied. Native dropdown renders OS-specific UI.
Option selectUpdates value, fires onChange event, closes dropdown. If value="" (placeholder), field is considered empty/unselected.
BlurFocus ring removed. Validation triggers if field has been touched. Error state applied if validation fails.
KeyboardArrow keys navigate options. Enter selects. Escape closes. Tab moves to next field. All native browser behavior.
DisabledCannot be opened or changed. cursor:not-allowed. bg:#F8FAFC, opacity:.75.
Filter barIn filter bar context, fires onChange immediately which re-filters the data — no submit button required.