Components · Forms

Select

Choosing one value from a known set. The component's defining risk is not how it opens — it is what it says before anyone has chosen.

Stable · v1.0 shadcn/ui WCAG 2.2 AA

Overview

A select looks like a low-stakes control and behaves like a high-stakes one, because it always shows something. Whatever is in the closed trigger reads as an answer, and if the form is submitted without the clinician ever opening it, that answer is recorded as theirs.

Everything below follows from that: an unanswered select must look unanswered, options must be readable in full, and no clinical value is ever pre-chosen.

Unanswered by default

An untouched select shows a placeholder, not a value. Nothing clinical is chosen on a clinician's behalf.

Fully legible

Every option is readable in full before it is chosen. An option a clinician has to guess at is a choice they did not really make.

Reversible

Changing a selection is as easy as making one, and never destroys anything else on the form.

Anatomy

Closed · unanswered, and open
Optional. Recorded with your assessment.
  • Early repolarisation
  • Pericarditis
  • Left ventricular hypertrophy
  • Artefact
  • Lead misplacement
ElementRule
Label Always a real <label for> outside the control. Same rule as Text field.
Trigger 44 px tall, --input border at ≥ 3:1. Placeholder text is visibly distinct from a chosen value, and not by colour alone.
Group headings Real grouping semantics, never a disabled option used as a divider.
Options Full text, wrapping if necessary. Never truncated.
Never pre-select a clinical value

A select showing the first option by default records that option every time a clinician does not notice the field. Anything with clinical meaning — a reason, a severity, a route, a site, a dose band — opens on a placeholder and stays invalid until chosen. The exception is narrow: a value the system genuinely knows, such as the acquiring device or the current user's unit, which is pre-filled and clearly marked as such.

Options

Options that look alike

A select presents its options in a small box, in a list, read quickly, often by someone who already believes they know which one they want. That is the worst possible presentation for a pair of names that differ by two letters — and clinical vocabularies are full of them.

The rule

Confusable options are never adjacent, and never distinguished by their name alone. If two options can be mistaken for each other, the list separates them and each carries something that tells them apart — strength, route, form, or the clinical context it belongs to.

Look-alike and sound-alike names are a recognised medication-safety hazard with published lists behind it, and a dropdown concentrates every condition that makes them dangerous: small type, tight leading, alphabetical order that puts the confusable pair next to each other, and a reader scanning rather than reading.

MitigationWhat it does Claim class
A disambiguating attribute on every option Strength, route or form beside the name. Two options that differ only in a name are two options that can be swapped; two that differ in name and route are harder to swap by accident. Reasoned
Confusable pairs separated in the ordering Alphabetical order actively creates the hazard by placing similar names together. Grouping by clinical category instead puts distance between them. Reasoned
Tall Man lettering Capitalising the differing part — the convention used on published confused-name lists. Adopt it if your formulary already uses it, so the screen matches the shelf and the chart. Convention. Widely used and endorsed; the experimental evidence for benefit is mixed rather than settled, and this system does not claim more than that.
The chosen option restated after selection The closed trigger shows the full option including its disambiguator, not a truncated name. This is where a mis-selection is actually caught. Reasoned

What a dropdown must not grow into

Every feature below is offered by mainstream systems, each solves a real problem, and each turns the control into something other than a way of choosing one value from a known set.

FeatureVerdict
A hyperlink among the options No. One item that navigates away, among items that select, is a category error — and it abandons a partly-filled form to do it. If the reader needs to go somewhere, that is a control outside the list.
Multiple columns with sticky headers No. That is a Data grid inside a transient surface, with none of a grid's semantics and none of its rules about truncation, sorting or keyboard traversal.
A filter field inside the menu Only where the list genuinely cannot be shortened, and then Escape must be unambiguous — it closes the menu, and clearing the filter is its own control. A filter that narrows to a single option never selects it automatically.
Select-all in a multi-select Only with the set named — "Select all 4 shown" or "Select all 19", per List. A bare "Select all" beside a filtered list is a coin toss.
Icons beside options No. There is no icon set here, and an option is text a clinician must be able to read aloud to a colleague.
Options that change while it is open No. A list reordering or re-populating under a pointer already moving is how the wrong option is chosen — the same objection as Reprioritisation. Changes wait for the menu to close.

The pattern is the one from Menu: a transient surface accumulates features because it is convenient to put them there, and each addition costs a protection the surface was never designed to provide. A dropdown that needs a filter, columns and a link is a panel that has not admitted it.

Native or custom

UseWhenWhy
Native <select> Simple lists, and all touch platforms The OS picker is larger, better at one-handed use, works gloved, and needs no custom keyboard handling. It is almost always the safer control on a cart.
Custom listbox Grouping, search, rich option content, multi-select Only where native cannot express it. Accepts the full cost of implementing keyboard, focus and announcement correctly.

A custom select that is merely prettier than the native one is not worth its accessibility surface. Reach for it when the requirement genuinely exceeds what native offers.

States and validation

Do

Unanswered looks unanswered. Nothing is recorded unless a clinician chooses it.

Don't

First option pre-selected. Every unattended form now records "Critical", and nobody chose it.

What the component enforces, and what it only asks for

A native <select>, deliberately — which means the platform holds more here than usual, including one behaviour this page argues against and cannot remove.

RuleHeld by How
Options are text, with no icon slotThe component SelectOption is a value and a label. There is no way to put a glyph, a link or a nested control in the list.
Asserted: Select: an option is a value and a label, with nowhere to put a glyph
The closed control restates the whole optionThe component A native select shows the selected option's full label, which is where a mis-selection is actually caught.
Asserted: Select: the closed control carries the whole option, not a truncation
An error is added to the hint, never substitutedThe component Same wiring as Text field.
Asserted: No component substitutes an error for its hint
Keyboard and screen-reader behaviourThe platform Everything a native select does on every platform, including on a touch device where it becomes the system picker.
Type-aheadThe platform Typing jumps to whichever option sorts first, and a native select cannot switch that off. This page argues type-ahead is a hazard among confusable names — that is an argument for not putting confusable names in a long select, not a behaviour the component removes.
Confusable options are separated and disambiguatedYou Grouping, ordering, Tall Man lettering and the strength-and-route suffix are all properties of the options array you build.
Nothing is pre-selected where the choice is clinicalYou defaultValue passes straight through.
Why this is written down

A rule stated on a component page reads as a rule the component keeps. 3 of these 7 are; 2 are obligations this page was quietly handing to the reader. The most important rule on this page — that two look-alike names are never adjacent and never distinguished by name alone — lives entirely in the data you pass.

Do's and don'ts

Do

Unanswered looks unanswered. Nothing is recorded unless a clinician chooses it.

Don't

First option pre-selected. Every unattended form records “Critical”, chosen by nobody.

Do
  • Left ventricular hypertrophy
  • Left ventricular hypertrophy with strain
  • Other…

Full option text, wrapping if needed, plus an explicit “Other” where the list may be incomplete.

Don't
  • Left ventricular hypertrophy
  • Left ventricular hypertrophy with strain

Truncated to the same visible string. Two different findings, indistinguishable at the point of choosing.

Do

Vasopressors

DOBUTamine 250 mg/20 mL · infusion

Antiarrhythmics

Amiodarone 300 mg/10 mL · IV bolus

Inotropes

DOPamine 200 mg/5 mL · infusion

The confusable pair is separated by grouping, and each option carries a strength and a route. Two things must go wrong, not one.

Don't
Dobutamine
Dopamine
Doxapram

Alphabetical order has placed three similar names together, with nothing to tell them apart. The ordering created the hazard.

Do

A long list gets a search with visible results — the reader sees what matched before choosing.

Typing narrows and shows. Nothing is selected by having landed on it.

Don't

Type-ahead: d-o-p jumps to whichever name sorts first.

Three keystrokes and a confusable name is selected without being read. This is the failure the section is about, automated.

Do
DOPamine 200 mg/5 mL · infusion

The closed control restates the whole option. This is where a mis-selection actually gets caught.

Don't
DOPamine 200 mg/5 mL · inf…

Truncated back to almost the bare name, discarding the attribute that was added to tell it from its neighbour.

Accessibility

Outcomes of use

What this contributes to, in the terms of Usability & context of use. These are attributes believed to contribute to an outcome; the outcome itself is settled by observing real use in a specified context, not by this page.

Clinical safety notes

Risk controls this page specifies

Trace these in your risk file (ISO 14971) and usability engineering file (IEC 62366-1). Which of these the component keeps and which are yours is stated in the guarantees table; a control the component does not keep is one your risk file must show you keep.

Implementation

$ npx shadcn@latest add https://md.notjustany.tech/r/select.json
<Select
  label="Infusion"
  hint="Strength and route are part of the option"
  placeholderOption="Choose an infusion"
  options={[
    { value: "dobu", label: "DOBUTamine 250 mg/20 mL · infusion" },
    { value: "amio", label: "Amiodarone 300 mg/10 mL · IV bolus" },
    { value: "dopa", label: "DOPamine 200 mg/5 mL · infusion" },
  ]}
/>

// Options are flat data with no icon slot and no link item, so a dropdown
// cannot grow into a navigation surface.

What the component takes. This table used to list placeholder, clinical, searchable, optionsError — props the component does not have, and never had. Found by the registry gate’s props-table rule.

PropTypeDefaultNotes
labelstring—Required.
optionsSelectOption[]— Required. Text only — there is no icon slot.
hintstring— What the field is for. Never removed when an error appears.
errorstring— Added below the hint, and described first.
placeholderOptionstring— The unselected state, as a first option with no value. Pass it wherever the choice is clinical: without it the first option is pre-selected, and nobody chose it.
NotJustAnyMed.Tech Design System · Select · v1.0 · draft for review
Reference applications named in this system are fictional; all patient data shown is fabricated.