ARIA Authoring Practices, implemented

The components that are
actually hard to get right.

Not buttons and cards. A focus trap that cannot be escaped, a combobox that keeps DOM focus in the input, a live region that actually announces. Eleven patterns, zero dependencies, no build step — plain ES modules, and about a third of the source is comments explaining why each decision is what it is.

What this is trying to prove

Most component libraries that advertise accessibility have a focus trap built on a single keydown handler for Tab. That handler is escapable in four ways: a click on a background control, a script calling .focus(), focus returning from the browser's own chrome, and a screen reader's virtual cursor, which does not use Tab at all.

The implementation here uses three mechanisms — inert on the background, a wrapping Tab handler, and a focusin backstop — because each one has a hole the other two cover. The reasoning for every such decision is written into the source, next to the code it explains.

Verification

187 automated assertions run in a real browser — real focus order, real inert, real layout — because jsdom implements none of those. Announcements are a separate matter: no automated tool can hear VoiceOver, so each component ships a manual test script in the README.

Run the test suite →