JM Family Design System

Select

Select lets users choose one value from a known list. Use it when choices are stable and compact, and when seeing every option at once is not essential.

Guidance for adoption

Start here before choosing examples or props. These notes explain where Select helps, where another pattern is better, and what should stay true in product work.

When to use

  • Known finite choices
  • Status filters
  • Compact single-choice fields

When not to use

  • Binary choices
  • Long searchable lists
  • Actions or navigation

Accessibility expectations

  • Use a visible label.
  • Ensure keyboard selection works without pointer input.
  • Announce validation state and selected value.

Content guidance

  • Write the label as the decision the user is making, such as "Request status".
  • Keep option labels short, parallel, and easy to scan in the collapsed menu.
  • Use helper text to explain how to choose when the options are not self-evident.
  • Do not hide consequences inside option labels; explain high-impact choices near the field.

Implementation notes

  • The component wraps a native select, so options and optgroups are passed as children.
  • Helper and error text are connected with aria-describedby; error also sets aria-invalid.
  • Use radio buttons when users need to compare all options or the list is very short.
  • Searchable, async, multi-select, and custom-option experiences need a different pattern.

Import

import { Select } from '@/components/ui/Select';

Wraps a native select with label, helper, and error wiring; options are passed as children.

States

Select states should behave like conventional form controls. The control can change border, surface, and message tone, but it should not move or animate.

Choose the status that best matches the request.

Default

Ready for a user to choose one value from a compact list.

Keyboard users can open and change the selection.

Focused

Uses a stable focus ring without moving the control.

Select a status before submitting the request.

Error

Tells users why the current state cannot continue.

Status is locked after final approval.

Disabled

Shows a value that cannot be changed in the current workflow state.

Anatomy

A select field is more than a collapsed menu. Its label, selected value, option set, and helper text need to work together so the choice is understandable before and after it is made.

Choose the status that best matches the request.

  1. Visible label
  2. Selected value
  3. Dropdown affordance
  4. Helper or error text
  5. Option list
  6. Focus and validation state

Props

The component accepts every native HTMLSelectElement attribute on top of the design system props below.

PropTypeDefaultDescription
labelReactNodeVisible label rendered above the select. Required for accessibility.
helperReactNodeGuidance text below the select. Auto-wired to aria-describedby.
errorReactNodeError message. Replaces helper text and sets aria-invalid on the select.
childrenReactNodeNative <option> elements passed as children of the select.

Usage rules

Use for compact, known choices

Select works well when the option set is stable, short enough to scan, and only one value can be chosen.

Do not hide important comparisons

If users need to compare all options before deciding, use radio buttons instead of a collapsed select.

Keep labels and helper text visible

The selected value should not be responsible for explaining the field. Labels and helper text carry that context.

Do not use for long searchable lists

For large lists, remote results, or typeahead needs, use a combobox/autocomplete pattern when it exists.

Known limitations

What Select does not do yet, and what consumers need to compose themselves.

  • Native select element only. Searchable, multi-select, async-loading, and custom-option rendering are not supported; product needs beyond a basic dropdown require a different component.
  • No required-field indicator and no leading-icon slot. Required asterisks and adornments must be rendered by the consumer outside the component.

Agent guidance

Agents should choose Select only when the choice set is known, compact, and single-select. Otherwise, use the component or pattern that better matches the task.

Generation rules

  • Use radio buttons when users need to compare all options at once.
  • Use autocomplete or combobox behavior for long or searchable lists.
  • Do not hide required context inside placeholder text.
  • Switch to radio buttons or checkboxes once the choice count drops below six. The native select hides options behind a click and slows scanning.
  • For multi-select, async loading, or filterable lists, reach for a combobox in product code; the native select element does not support those modes.
  • Place the required asterisk in the label and add aria-required="true" on the select element. There is no required prop, and a placeholder option labeled "Select one" is not an accessible required indicator.
  • When the list exceeds about fifteen options, group them with optgroup elements; do not invent custom dividers inside the option list.

Baseline example

import { Select } from '@/components/ui/Select';

<Select
  label="Request status"
  name="requestStatus"
  defaultValue="pending-review"
  helper="Choose the status that best matches the request."
>
  <option value="pending-review">Pending review</option>
  <option value="approved">Approved</option>
  <option value="needs-info">Needs information</option>
</Select>
If users must search, create new options, choose multiple values, or compare many options, agents should not force the experience into Select.

Decision standard

Select is a compact choice control, not the default answer for every option list. Use it when compactness matters more than side-by-side comparison.