Command Menu

How the Command Menu works with a keyboard and assistive tech, and where it stands against WCAG 2.2 AA.

AAWCAG 2.2 target
6/8contrast pairs passing
6keyboard interactions

The Command Menu follows the WAI-ARIA combobox pattern: focus stays in the search field, the arrow keys move a highlight through a listbox of results, and aria-activedescendant tells the screen reader which result is current. One result is always highlighted, so Enter always has a destination.

Keyboard#

↓

Highlights the next result, passing over group labels. Wraps from the last to the first.

↑

Highlights the previous result. Wraps from the first to the last.

Enter

Runs the highlighted result.

Esc

Clears the query and the filter. With nothing to clear, closes the menu.

Tab

Leaves the field for the clear button, then the filter tags. Results are not tab stops.

⌘+K

Opens the menu. The host binds this shortcut; the component does not.

Semantics#

role="combobox"

With aria-autocomplete="list", aria-controls on the results and aria-expanded="true", since the list is always shown.

Search field
aria-activedescendant

Points at the highlighted option, so it is announced while focus stays in the field.

A result is highlighted
role="listbox"

Named Results. Each group inside is role="group", labelled by its heading.

Results
role="option" aria-selected

aria-selected="true" on the highlighted row only.

Each result
aria-pressed

Inside a group named Filter results. The chosen tag is pressed.

Filter tags
aria-live="polite"

A hidden line says how many results there are after every change.

Result count
aria-hidden="true"

The key hints repeat what the keyboard already does, so they are hidden.

Footer
<dialog>

Shown with showModal(), so the page behind is inert. Give the dialog an aria-label (Command menu); the preview does not.

Opened as a dialog

Colour contrast#

Every variant and state has to meet WCAG 2.2 Level AA. Measure the colours as they land on screen: a translucent hover or press wash over whatever sits behind it.

4.5:1

Result text · Rest, Highlighted

14px titles (#2a2a2a) and descriptions (#6d6d6d) against white and the 4% highlight wash.

WCAG 1.4.3 Contrast (Minimum) ↗
4.5:1

Field, tags and footer · Always

Group labels and unchosen tags are #6d6d6d on white (5.17:1); a chosen tag is white on #2a2a2a (14.35:1); footer hints are #6d6d6d on #f2f2f2 (4.62:1). The #8f8f8f placeholder measures 3.23:1, which is allowed only because the field also has an aria-label.

WCAG 1.4.3 Contrast (Minimum) ↗
3:1

Highlighted row · Highlighted

The highlight is the keyboard's focus indicator here, and its 4% wash measures 1.09:1 against white. It does not show reliably.

WCAG 1.4.11 Non-text Contrast ↗WCAG 2.4.7 Focus Visible ↗
3:1

Focus indicator · Field, clear, tags

The field, clear button and tags ring in #1a6ef8 (4.54:1 on white), with a white gap on the field and tags.

WCAG 1.4.11 Non-text Contrast ↗WCAG 2.4.13 Focus Appearance ↗

Measured contrast#

Text in a result row against the row, at rest and highlighted. The shortcut key and badge carry their own fills, so the highlight does not reach them. 2 of 8 pairs fall below their minimum (4.5:1 for text, 3:1 for graphics) and are marked in amber.

PartRestHighlighted
Result · Title14.35passes13.17passes
Result · Description5.17passes4.75passes
Result · Shortcut key5.17passes5.17passes
Result · Badge3.56below the minimum3.56below the minimum

Motion#

  • Row, tag and field colour changes take 100–120ms and are turned off under prefers-reduced-motion.
  • Opened as a dialog it rises 6px and fades over 200ms only when motion is allowed.
  • Moving the highlight scrolls the list to the nearest edge, without smooth scrolling.

Checklist#

The highlighted row is a 4% wash, about 1.1:1 against white. Give it a stronger fill or an outline before the code library ships; it is the only sign of where the keyboard is.

The badge (#229a14 on #f4fef2) is below 4.5:1: see the table.

When it opens as a dialog, name the dialog and put focus in the search field. Closing it should return focus to whatever opened it.

Bind ⌘K (and Ctrl K) in the host, and make sure it does not override a shortcut the page or the screen reader relies on.

Keep result titles unique enough to tell apart when read alone: Roadmap Q4, not Roadmap twice.

Rows are 48 or 64px and tags 26px, all over the 24px target minimum. The clear button is 26 × 30px.