accessibility · keyboard
Focus model
WCAG 2.4.7 (Focus Visible · Level AA) requires "any keyboard operable user interface has a mode of operation where the keyboard focus indicator is visible." TUX guarantees this across every focusable surface.
the indicator
Visible focus ring
Every focusable element gets a 2px maroon outline with a 2px offset on :focus-visible. Mouse-click doesn't trigger the ring (avoids the "ring on every button I click" noise); only keyboard navigation does.
/* Universal focus ring — every focusable surface inherits this */\n*:focus-visible {\n outline: 2px solid var(--brand-primary);\n outline-offset: 2px;\n border-radius: var(--radius-sm);\n}Three exceptions:
- Inputs / textareas use a ring + a subtle border-color shift so the entire field reads as focused, not just the outline.
- Cards (linked) use a corner-drop hover + focus tint instead of an outline — the chrome IS the indicator.
- HC theme bumps outline-width to 3px and uses pure black for guaranteed contrast.
trapping focus
Modals, slideovers, popovers
When an overlay opens, focus moves into it and is trapped until the overlay closes. Components that own this:
TuxModal— focus moves to the first focusable element; Esc closes; Tab cycles only within the modal.TuxSlideover— same focus-trap behavior; built on the native<dialog>which provides the trap for free.TuxShortcutsHelp— modal overlay triggered by ?; focus traps in the dialog.TuxCommandPalette— composes Reka UI's command primitive; same trap.
On close, focus restores to the trigger element — clicking "Close" returns the keyboard to the button that opened the overlay, not the top of the document.
tab order
Document order, with rare overrides
TUX components render their internals in semantic document order. tabindex="-1" is reserved for two cases:
- Skip-link target — the
#main-contentwrapper hastabindex="-1"so it can receive programmatic focus from the skip link without being part of the normal tab sequence. - Roving tabindex inside composite widgets — menubars, listboxes, treeviews. Arrow keys move within; Tab moves to the next widget. Reka UI provides this behavior for its own primitives.
Positive tabindex values are forbidden — they create unpredictable jumps and break user expectation. If a piece of content needs to be reached earlier, restructure the DOM order, don't reorder the tab sequence.
testing
How to verify a page
- Press Tab from the top of any page; the skip link should appear first.
- Continue tabbing — every interactive element must show a visible focus ring.
- Open any modal / slideover / shortcuts-help; Tab must cycle within (not escape to the page behind).
- Close the overlay; focus must return to the trigger.
- No
tabindexvalues > 0 anywhere — search the built HTML with browser devtools to confirm.