Requirements
Accessibility
Every control ships a keyboard path, a visible focus ring drawn from tokens, and a color pairing that clears WCAG AA. The table below measures the live theme — toggle it in the sidebar to validate both palettes.
Color contrast
Ratios are computed in the browser from the resolved token values. Text pairs must reach 4.5:1, and non-text pairs such as borders and the focus ring must reach 3:1.
Measuring…
Focus states
One indicator for the whole system, drawn from --focus-ring, --focus-ring-width and --focus-ring-offset. It falls back to the system highlight color under forced-colors mode. Never set outline: none on a control; re-point the tokens instead.
Tab through these to verify the ring in the current theme.
Your plan is limited to 10 seats.
Keyboard navigation
Button
- Tab reaches every enabled button; Enter and Space activate it.
- Disabled and loading buttons are removed from the tab order by the native disabled attribute.
- Loading state sets aria-busy and announces its label through a polite live region.
- size="sm" keeps a 44x44 pointer target even though it renders smaller.
Input
- The label is programmatically associated, so clicking it focuses the field.
- Hint and error text are linked with aria-describedby; errors also use aria-invalid and aria-errormessage.
- Errors are announced immediately via role="alert".
- Focus is shown on the whole field shell, not just the bare input.
Checkbox
- Tab reaches the box; Space toggles it.
- The indeterminate state reports aria-checked="mixed" to screen readers.
- The 20px box carries a 44x44 target; the label is also a click target.
Modal
- Focus moves to the dialog panel on open and returns to the trigger on close.
- The native dialog element traps Tab inside the dialog and makes the page behind inert.
- Escape closes a dismissable dialog; the close button is the first tab stop.
- Non-dismissable dialogs must always provide a footer action that closes them.
Open the dialog, tab through it, press Escape, and confirm focus lands back on this button.