Positions

Accessibility

WCAG AA is the floor, not the goal. Conformance matters and it is often a legal requirement, but it is not a measure of whether the thing works. The test that matters is whether someone using a screen reader, a keyboard, magnification or voice control can do what they came to do, comfortably.

The audit is the last line of defence, not the first. If an audit is finding problems cold, the process upstream has already failed; formal gates should confirm evidence the tooling has already produced.

Conformance is not usability

Three arguments, in ascending sharpness.

A page can pass every checkpoint and still be unusable. Conformance is a property of the markup; usability is a property of the journey, and only one of them is what the person came for.

Automation catches the easy part. Automated checks run on every commit and catch regressions, but they cover only the part of the standard a machine can judge, which is well under half the barriers users meet in practice. Focus order, whether a journey can be completed, whether a screen reader conveys the page: all judgement, all manual.

The standard itself is a compromise. WCAG 2.x contrast is a luminance ratio: it scores dark-on-light and light-on-dark identically and has no concept of text size, so two pairings that both pass can read very differently. APCA models how contrast is perceived. Meeting AA is not the same as being readable, which is worth saying whenever a passing contrast checker is treated as the end of the conversation.

Where accessibility lives decides what it costs

If accessibility lives in the design system, every page inherits it. If it lives in a QA gate, every page has to earn it again.

Each component ships with semantic structure, keyboard operation, focus management, contrast and screen-reader behaviour already handled, as properties of the component rather than fixes applied later. On any project of scale this is the single decision that pays back most, and it is why our design systems position and this one are the same argument from two ends.

Tokens are an accessibility control, not a naming convention. Foreground and background semantic tokens are defined and checked as contrast pairs, so any component referencing them meets the standard in every theme, mode and palette the tokens resolve to. A hardcoded value might pass contrast against the background it was written for and fail on the next surface, with nothing to catch it. When a pipeline rejects a hardcoded value, it is refusing a change that has opted out of the contrast system.

The enforcement runs as a chain, and every link confirms what the previous one produced:

Stage Control
Design system Contrast pairs in the tokens; semantic structure, keyboard operation, focus management and screen-reader behaviour inside each component; accessibility-tested unstyled primitives underneath
Design Design tooling mirrors the coded system, so a design cannot introduce a pairing the tokens disallow. Review pass in the browser, against the real rendering
Build Lint and pre-commit hooks reject hardcoded values used in place of semantic tokens
Design-system pipeline Automated checks against every component in every state and variant, plus visual regression, before publish
Application pipeline The same checks against rendered pages. Quality gates block failures
Manual testing Guided checkpoint passes, screen readers, keyboard-only operation, contrast across interaction states
Independent audit External specialist, underpinning the VPAT and ACR

How it is tested, and what that costs

Four layers, each covering what the one before cannot.

Layer What runs What it covers
Automated axe-core against the rendered DOM on every change; eslint-plugin-jsx-a11y at lint time Regressions. Machine-judgeable criteria only
Manual axe-guided checkpoint passes; Colour Contrast Analyser across interaction states Judgement: journey completion, focus order, coherence
Assistive technology NVDA and equivalents, keyboard-only operation What a screen-reader and keyboard user experiences
Visual regression Playwright Drift across component states and viewports

Automated checks confirm nothing has regressed. They do not confirm conformance, which is what the manual and assistive-technology layers, and the independent audit, are for.

The automated half is free, and there is no need to introduce paid accessibility tooling as a baseline. axe-core in CI, eslint-plugin-jsx-a11y, the axe browser extension, NVDA, Colour Contrast Analyser and Playwright visual regression are all free or open source. The two paid items are optional and specific: axe DevTools Pro, per seat in the low hundreds a year, buys guided manual tests worth having when manual testing needs to be repeatable rather than dependent on who is testing that week, and the independent audit is a client-borne pass-through. Guided tests also reduce what the independent audit finds, which is the expensive end.

What an honest conformance report looks like

VPAT is the template, published by the ITI, with editions for Section 508, EN 301 549 and WCAG. ACR is the completed report: a conformance level per success criterion, Supports, Partially Supports, Does Not Support or Not Applicable, with remarks explaining each. It is a procurement instrument, not an engineering one, and an honest one lists Partially Supports entries with specifics. An all-Supports ACR with empty remarks is a red flag to anyone who reads them regularly.

  • The ACR should be underpinned by an independent audit, not self-authored, so its declarations rest on third-party evidence.
  • An ACR is a snapshot of a version at a date. On a continuously shipping product, one report at launch is stale on arrival, so the cadence follows the release rhythm: a baseline at first major release, refreshes at significant milestones, a full re-issue at launch, then annually or at any release that materially changes templates or components.
  • Scope it accurately. An ACR can warrant a platform and component system, which is what conformance by construction covers. It cannot warrant an evolving content estate written by many authors; that is governed through migration QA and authoring guardrails instead.

Charts are where accessibility is authored, never inherited

SVG is invisible to assistive technology by default, and no chart is fully accessible on its own. That makes the charting library an accessibility decision. A vanilla primitives approach, visx or D3's modular packages, ships with no accessibility at all: a liability for a team hand-rolling each chart, an asset for a design system, because the accessible pattern is built once and every chart inherits it. An all-in-one framework gives partial defaults and takes away the markup control needed to beat them.

Every chart ships in three forms, none of which is a fallback.

Form What it is
The message A sentence in body copy naming the chart type and the trend it shows, not an alt attribute
The data A structured HTML table equivalent, and a machine-readable download
The structure The chart as navigable content: ARIA graphics roles, keyboard entry, arrow-key movement through points and series, values announced on focus

This is not progressive enhancement, and the distinction matters. Progressive enhancement makes the table the baseline and the chart the enhancement, which quietly makes the accessible forms the fallback tier. For trend and pattern questions a raw table is the worst format for a screen-reader user, so treating the chart as the enhancement hands assistive-technology users the weakest tool for the questions charts exist to answer. The data is the foundation, and the sentence, the table and the navigable chart all render from it. Enhancement by device capability is legitimate. Enhancement by reader ability is not.

The components enforce the rest: colour is never the only channel and palettes are colourblind-safe in the token layer, nothing lives on hover alone, charts reflow and survive 200% zoom, and motion respects reduced-motion preferences.

The industry's AI patterns are poor for assistive technology

The interaction patterns the industry has settled on for AI features are, as a set, poor for assistive technology, and none of the fixes needs new technique. It needs refusing patterns that were normalised before anyone tested them with a screen reader.

Pattern Problem What to do instead
Streamed word-by-word output The region keeps mutating, so screen readers re-announce or fall silent Render answers as finished, structured content, announced once
Chat transcripts Weak semantics, no landmarks to navigate by Ordinary page content: headings, lists, links
Typing indicators, chips, feedback controls Routinely visual-only or unreachable by keyboard Ordinary buttons and announced state changes
Bare superscript citations No context out of order Real links with accessible names

Multilingual work is an accessibility surface

Not a parallel workstream. Mixed-language pages make language-of-page and language-of-parts live on nearly every page, and a mis-declared lang has a screen reader pronouncing one language with another's phonemes. Right-to-left goes beyond mirrored layouts: focus order must follow reading order, and bidirectional text must keep numerals reading correctly inside RTL prose. Scripts without word spacing affect text-to-speech segmentation the same way they affect search analysers, and minimum comfortable type sizes differ by script, which interacts with the contrast position above. Practically, assistive-technology testing runs per locale, not once in English.

What holds at scale

Accessibility that depends on author diligence fails at scale. The content model does the enforcing: authors supply data and meaning, components supply the accessible rendering, and the authoring experience makes the accessible path the only path, with required text descriptions, structured tables as data rather than markup, and guardrails in the authoring spec. Where description-writing is the burden, AI-assisted drafting with human sign-off is what keeps it viable across many languages rather than quietly skipped in most of them.

Governance is what stops all of this decaying: a named owner for accessibility at the experience layer, a standing item at release readiness on every release, and exceptions that cannot be waived inside the team but escalate as a decision with an owner, a rationale and a remediation date. In run state, ownership transfers with design-system stewardship. What gets left behind is the tooling, the reusable test suites, the audit relationship and the ACR itself, so conformance is sustained and regressions caught as the product evolves rather than discovered at the next audit.

Reviewed 2026-08-27 Andrew Flett

Source: raw markdown, also served at this URL under Accept: text/markdown.