Accessible component showcase
Five production-grade widgets built with vanilla JavaScript and hand-written CSS. Correct focus management, ARIA state that never drifts from the visual, and full keyboard operability by design.
Modal dialog
A focus-trapped, modal surface that disables the page behind it and returns focus to its trigger on close.
The dialog has not been opened yet.
Keyboard Tab cycles inside· Esc closes, focus returns· backdrop click closes· page behind is inert
Tabs
Roving tabindex with aria-selected, aria-controls and aria-labelledby wired end-to-end. Hidden panels are truly removed from the a11y tree.
What this component does
Tabs let users switch between large related views without leaving the page. The selected tab is always reachable with a single Tab press, and arrow keys move between tabs without hunting for focus.
Dropping it into your code
import { Tabs } from '@clarity/tabs'; Tabs.mount(document.querySelector('#docs-tabs'), { default: 'overview', animated: true });
The Usage tab carries a badge with a count — a visual affordance that never affects the tab's accessible name.
Why these patterns
| Property | Value | Meaning |
|---|---|---|
| tabindex | 0 on selected only | one stop in the tab order |
| aria-selected | true / false | announcement on selection |
| hidden | on inactive panels | content leaves the a11y tree |
| ← / → | roves focus | with wrap-around |
Keyboard ←→ move focus & select· Home/End first/last· Tab enters panel content
Combobox
An autocomplete input using the aria-activedescendant pattern: the listbox is never focusable, and the highlighted option is tracked on the input itself.
Start typing to search 20 cities. Arrow keys highlight, Enter selects.
Keyboard type to filter· ↓↑ move highlight· Enter selects· Esc closes & reverts
Accordion
A disclosure group where any number of regions may be open at once. Height animates first; hidden is only touched at the end of the transition.
Install from the registry and add the stylesheet once:
npm install @clarity/ui @clarity/styles
Clarity UI ships per-component entry points, so only the code you use ends up in your bundle.
Every color, radius and duration is a CSS custom property, documented in one constants block:
--accent·--ink·--paper— the palette--sp-1…--sp-7— the spacing scale--dur-1…3·--r-sm…lg— motion and shape
Override any token on :root and the whole system re-skins.
- Landmarks: one
main, labellednavregions - Headings: a single
h1, oneh2per section - Focus: visible 2px ring everywhere, never removed
- State:
aria-expanded/aria-selectedalways mirror the UI - Motion: honours
prefers-reduced-motion
Keyboard Tab reaches every trigger· Enter/Space toggles· multiple regions may be open