---
alwaysApply: false
globs: ["**/*"]
description: "Keyboard reachability, focus order, ARIA roles and accessible labels. Use when building a form, dialog, menu or custom widget."
---

# UI Controls And Semantics

**Scope.** Keyboard paths, focus movement, roles, names and error
association. Contrast, target size and motion belong to
`ui-accessibility`. WCAG references are level A or AA.

**Native element first.** Produce the native control that already carries
the role, state and keyboard behaviour: `button`, `a[href]`, `input`,
`select`, `details`. Add an ARIA role only where no native element
exists. A reviewer counts `role=` attributes and asks which native
element each one replaces.

**Keyboard reach, no trap.** Produce a keyboard path to every action
reachable by pointer, and a keyboard exit from every focus container (SC
2.1.1, SC 2.1.2). A dialog releases focus on Escape. A reviewer unplugs
the mouse, completes the surface's primary task, leaves every container,
and writes down the key sequence.

**Focus order.** Produce a tab order matching the visual reading order
(SC 2.4.3). `tabindex` is 0 or -1 only; a positive value is a defect. A
reviewer tabs through once and reads the stops top to bottom, left to
right.

**One tab stop per composite widget.** Produce arrow-key movement inside
menus, tab lists, list boxes, trees, grids and toolbars, with the widget
itself a single tab stop. A reviewer checks that Tab skips the interior
and arrow keys move within it.

**Fixed keys.** Produce Enter and Space to activate a button, Space to
toggle a checkbox, Enter to submit a form, Escape to close an overlay,
Home and End to jump within a list. A reviewer tries each key on each
control type.

**Dialog focus.** Produce focus moved into the dialog on open, confined
while open, and returned to the invoking element on close. A reviewer
opens and closes a dialog three times and lands on the trigger each time.

**Accessible name.** Produce a name for every control from visible label
text: `label[for]`, or `aria-label` on an icon-only control repeating its
tooltip word for word (SC 4.1.2, SC 2.5.3). A placeholder is never the
label. Wrap radio and checkbox groups in a `fieldset` with a `legend`. A
reviewer reads the accessibility tree, finds no control named only
"button" or left unnamed, and reads one label out of context to name its
group.

**Error association.** Produce the error in text beside the field, linked
by `aria-describedby`, with `aria-invalid` set, plus a correction
suggestion wherever the rule is known (SC 3.3.1, SC 3.3.3). A reviewer
submits an invalid form with a screen reader and hears field, error and
suggestion.

**Announcements.** Produce one `aria-live="polite"` region per surface for
status; `assertive` only when the person must stop. A reviewer triggers a
background save and hears exactly one announcement.

**Structure.** Produce one `h1`, headings nested with no skipped level,
and one `main` landmark alongside `banner`, `nav` and `contentinfo`. A
reviewer lists the headings and reconstructs the surface's outline from
that list alone.

**Blocked controls.** Produce `aria-disabled="true"` plus a stated reason
when the person needs to know why. Use `disabled` only when the reason is
already on screen. A reviewer tabs to a blocked control and learns why.
