Web UI Accessibility Baseline¶
This document states the accessibility baseline the sqi-server web UI commits
to. It is intentionally modest — a floor, not a ceiling — so future contributors
know the target and do not regress it. Anything below counts as a bug; going
further is welcome.
The audience is operators using a keyboard-and-screen-reader workflow or working in varied lighting on varied displays, not a formal WCAG 2.1 AA certification effort. The UI has no auth flows or modal-heavy interactions today, so the baseline is correspondingly focused.
The three commitments¶
1. Everything interactive is reachable and operable by keyboard¶
- Every control a user can click — nav links, filter pills, sort headers, row
actions (cancel, retry, enable/disable), bulk-action buttons, pagination, copy
buttons, the submit form, and the log-viewer controls — must be reachable with
Tab/Shift+Taband operable withEnter/Space. - Use real semantic elements:
<button>for actions,<a>/<NavLink>for navigation, native<input>/<select>for form controls. Do not attach click handlers to bare<div>/<span>. Native elements are focusable and key- operable for free; a<div onClick>is neither. - Focus must be visible. Do not remove focus outlines without replacing them with
an equally clear
:focus-visiblestyle. - Interactive elements that toggle or select state expose that state to assistive
tech (e.g.
aria-pressedon toggle pills,aria-currenton the active nav link,aria-sorton sortable column headers,aria-checkedon selection checkboxes). - No keyboard traps: opening the slide-in log panel or any popover must not strand
focus;
Esc/closing returns focus to a sensible place.
2. Color usage meets WCAG AA contrast¶
- Text and meaningful UI graphics meet the WCAG 2.1 AA contrast minimums against their background: 4.5:1 for normal text, 3:1 for large text (≥ 18.66 px bold or ≥ 24 px) and for the visual boundary of essential controls and status indicators.
- The design tokens in
web/src/styles/tokens.cssare the single source of foreground/background pairings. When adding or changing a color, verify the resulting pairing meets the ratio above before committing — do not hand-pick ad-hoc colors in a component. - Color is never the only signal. Status is always carried by text as well as hue (see commitment 3); a red/green distinction must remain intelligible to a user who cannot distinguish red from green.
3. Status badges and icons have text alternatives¶
- Status is conveyed by a visible text label, not color alone. The
StatusBadgecomponent renders the status name (running,failed,succeeded, …) as text inside the colored pill, so the meaning survives grayscale rendering and screen readers. - The WebSocket
ConnectionStatusBadge(the colored connection dot) must carry a text equivalent — a visible label and/or an accessible name (aria-label/title) such as "Live updates: connected" — so its meaning is not purely the dot color. - Icon-only controls (e.g. a copy button rendered as just an icon) have an
accessible name via
aria-labelor visually-hidden text. Purely decorative icons are hidden from assistive tech witharia-hidden="true". - Non-text content that conveys information (progress bars, the task-progress
fraction) also exposes its value as text or an appropriate ARIA attribute
(e.g.
role="progressbar"witharia-valuenow/aria-valuemin/aria-valuemax).
What is explicitly out of scope for this baseline¶
These are not regressions to file against; they are deliberately deferred:
- Formal WCAG 2.1 AA conformance auditing and a published VPAT.
- Full screen-reader walkthroughs of every view with assistive-tech matrices.
- Reduced-motion, high-contrast-mode, and forced-colors theming.
- Localisation / RTL layout.
- Automated accessibility gating in CI (axe-core or similar). Encouraged later; not required now.
How contributors uphold this¶
- Tab through your change. Before opening a PR, navigate the affected view with the keyboard only. Every control you added must be reachable, operable, and show a visible focus ring.
- Prefer semantic HTML over ARIA. A correct native element beats a
divpatched withroleandtabindex. Reach for ARIA only to fill a genuine gap. - Pull colors from tokens and confirm contrast for any new pairing.
- Give every non-text indicator a text equivalent — a label, visually-hidden text, or an ARIA value.
- Spot-check with a screen reader (VoiceOver on macOS, NVDA on Windows) when you add a new interactive pattern.
See web-development.md for the development workflow and the
CONTRIBUTING.md "Web UI contributions" section for the component and testing
conventions these checks fit into.