Accessibility

Spark's WCAG 2.2 AA conformance target, what is automatically verified, and what a consuming portal must still provide.

Spark targets WCAG 2.2 AA. This page states what that means in practice, what is verified automatically on every change, and — importantly — what it does not cover.

What Spark is, for conformance purposes

Spark is a component library, not a website. Conformance obligations for a customer portal (including BFSG / EN 301 549 duties) land on the portal operating it, not on this package. Spark ships no user-facing strings — not even aria-label="Close", because portals are multi-language and the library cannot translate.

So a green Spark build does not make a portal conformant. These remain the consumer's:

The portal must provideWhy Spark cannot
Accessible names for icon-only controlsSpark ships no strings; names arrive as props
lang on the documentOutside any component
Page titles, heading orderDetermined by page composition
Skip links / landmark structureDetermined by page composition
Focus management across route changesOwned by the portal's router

What is verified automatically

Verification is split by what each layer can actually observe. jsdom has no layout engine and no computed colour, so contrast, geometry and motion are invisible to it — which is why a browser layer exists at all.

LayerVerifiesRuns
Palette (pure functions)contrast ratios for arbitrary customer brand hexes — 1320 comparisons over a fixed 165-hex sample gridevery test run
Semantic (jsdom + axe)roles, accessible names, hidden decoration, disabled semanticsevery test run
Rendered (Chromium + Playwright)contrast, target size, focus ring, reduced motion, focus-not-obscured26 state pages per run
Static (oxlint jsx-a11y)keyboard operability — an element taking a click without a role or key handlerevery push

Automated tooling detects roughly a third of WCAG failures. It cannot judge whether an accessible name is meaningful or a focus order logical, so each component's documentation carries a human verdict alongside the automated result.

Two different target-size numbers

  • 24×24px (2.5.8 Target Size (Minimum), AA) — the conformance bar. Fails the build.
  • 44×44px (2.5.5 Target Size (Enhanced), AAA) — Spark's house target. Reported, never blocking.

A control between the two is above the bar and below our intent. Findings in that band are listed in each run's report artifact — tracked, never blocking.

Known deviations

Recorded rather than hidden. Each is gated by a baseline that can only shrink: a new violation fails the build, and a fixed one must be removed from the baseline explicitly.

Total baselined at generation time: 2035 instances across 7 rules.

RuleComponents affectedInstancesNote
button-name51344Demo authoring: docs demos render bare controls with no accessible name. A defect in the examples, which readers copy — not in the components.
color-contrast6271One intentional waiver: Button and Toggle with styleVariant="solid" and color="neutral", under any neutralColor, keep white text that misses 1.4.3’s 4.5:1 bar in light appearance, because APCA (WCAG 3’s draft contrast model) rates white the more readable ink there and no ink satisfies both metrics — these cases stay until a palette change lets one ink pass both. The rest are concentrated in data-style × data-high-contrast combinations — the fill-leakage trap the theming contract §123 predicts.
aria-progressbar-name2168Progress elements in demos rendered without a name.
scrollable-region-focusable3120A scroll container that is not keyboard reachable. Note ScrollArea’s viewport is deliberately not focusable — see breaking-changes.
target-size-24360Controls under the 24×24px AA floor (2.5.8).
target-size148Reported by axe’s own target-size rule.
label124—

Two further deviations are behavioural rather than measurable by the sweep:

  • 2.5.7 Dragging Movements — zoomable charts. LineChart / PowerHistoryChart can only zoom in by drag or pinch; the reset control only zooms out. 2.5.1 is met (drag is a single-pointer alternative to the pinch) but 2.5.7 needs a non-dragging path, and "dragging is essential" does not apply.
  • Coverage debt. 20 components still lack an automated a11y test and 33 documentation pages still lack their ## Accessibility section. Both are gated by allowlists that can only shrink, so this number cannot grow.

Reporting an accessibility problem

Open an issue against this repository. Include the component, the theme state (appearance, style, high-contrast), and the assistive technology used — the state matters, since several findings appear only in specific data-style combinations.

On this page