Accessibility
Every component ships its own semantics. None of it is optional, and none of it depends on you remembering to add an attribute.
What the components guarantee
Interactive elements are real elements. A button is a button, a dialog is a native dialog opened with showModal(), and a link that navigates is an anchor. Focus containment, Escape handling and page inerting come from the platform rather than from a hand-rolled trap that works until someone opens a second overlay.
- Every control is reachable and operable from the keyboard.
- Focus is always visible. Interaction states are colour-only, so a focus ring is never the thing being restyled.
- State is announced, not implied:
aria-expanded,aria-pressed,aria-currentandaria-invalidtrack the component’s own state. - Anything conveyed by colour is also conveyed some other way — a word, an icon, or a shape.
- Motion respects
prefers-reduced-motion. Where an animation carried meaning, the meaning stays and the movement goes.
What is still yours
A component cannot know what a control is for. These are the places where the kit takes a prop and cannot invent a default.
| Yours | Why it cannot be automatic |
|---|---|
| Accessible names | An icon-only button needs a verb only you know. Every such component takes a label prop and several warn in development when it is missing. |
| Heading order | Components render the heading level you ask for. Only the page knows whether a card title is an h2 or an h4. |
| Alt text | MediaGallery makes it a required field rather than an optional one, because a gallery is exactly where empty alt text accumulates. |
| Language and direction | Set lang and dir on the document. Components use logical properties throughout, so RTL works once the document says so. |
How it is checked
Claims like these rot unless something enforces them. Every component and every documentation route is rendered to static markup in a test harness, and the output is asserted against a set of rules:
- No duplicate
idon a page. - No
aria-labelledbyoraria-describedbypointing at an element that does not exist. - No form control without a label, and no button without a name.
- No skipped heading levels.
Contrast is measured in a real browser against computed colours rather than against the palette, because a token is only as good as the pair it ends up in.
useId(). Two instances of the same component on one page will otherwise collide, and a colliding id silently points a label at the wrong control.Testing your own screens
The two checks that catch the most, fastest: tab through the screen without touching the mouse, and read it with the colours removed. If a state disappears in greyscale it was carried by colour alone, and if a control cannot be reached by keyboard it does not exist for a real share of your users.