Quality

Accessibility

A sweep of every public page and every story, in light and dark, against WCAG 2.2 AA.

What it checks

yarn a11y builds the blog, docs, marketing site, and Storybook, then opens every page and story in Chromium, in both color schemes. For each one it checks:

  • Roles and names — each page exposes the landmarks, headings, and labeled controls listed for it in scripts/a11y/expectations.mjs.
  • axe violations — against WCAG 2.2 AA, using axe.
  • Contrast — reported, but doesn't fail the run.

Known violations are recorded in scripts/a11y/baseline.json. The sweep fails on anything above the baseline, so it can't get worse.

Run part of it

yarn a11y --only docs

Surfaces are blog, docs, web-static, and storybook. The report is written to a11y-report/report.md.

Add a page

Add the route to the surface's pages in scripts/a11y/scan.mjs, then list what it must expose in expectations.mjs:

"/how-bones/get-started/installation/": [...DOCS_CHROME, h1("Installation")],

Fix something

After fixing a known violation, lower the baseline so it can't come back:

yarn a11y:update

Build an accessible component

  • Name every control. A button with only an icon gets an aria-label. A table, tab bar, or matrix takes a label prop.
  • Keep focus visible. Never remove an outline without a replacement. The design system's focus ring is --bones-shadow-focus.
  • Add a story in both states it matters. The sweep checks every story in light and dark, so a story is how a component gets checked.

Contrast failures are listed in the report by text and background token. They're design decisions, so they're reported, not failed.

Not covered yet

  • The desktop app isn't swept.
  • Keyboard navigation and screen readers are tested by hand, if at all. axe can't judge either.