Accessibility

WCAG 2.2 AA as a floor: axe at zero, 44 px targets, visible focus, colour never alone, reduced motion respected; each element's passport (point 11) says how it meets them.

Foundation · stable · v1.0.0 · owner: Site system lead · contract 19 of 20 points (open: figma)

Reference

Source reference; not an executed check.

axe
0
targets
44 px
focus
--focus ring, 3 px

Do and don't

2 positive / 2 negative authored documentation examples (2 each required); 1 reference (1 required); 0 failed. References and failures do not count; this is not behavior acceptance.

Do: Name the destination

Authored by accessibility.ts

Rendered consumer example; not an executed correctness check. button Isolated document follows the browser's colour and contrast preferences. The outer theme toolbar does not control this document.

Open example: Accessibility · Do: Name the destination Use the full-page example to follow page links.

The native link has visible words and a matching destination; the foundation's reference targets are not this example's measured accessibility result.

Do: State meaning beside its mark

Authored by accessibility.ts

Rendered consumer example; not an executed correctness check. band-word Isolated document follows the browser's colour and contrast preferences. The outer theme toolbar does not control this document.

Open example: Accessibility · Do: State meaning beside its mark Use the full-page example to follow page links.

The actual BandWord supplies written meaning alongside colour instead of requiring the reader to decode a dye.

Don't: Colour is the entire status message

Authored by accessibility.ts

Rule illustration; not an executed check. accessibility / a11y.colour-alone

<span style="background:var(--teal)"></span>
No status word or equivalent meaning is supplied.
This illustrated misuse withholds the meaning from readers who cannot distinguish the mark; it is not an executed accessibility check.

Don't: The only link content is a silent icon

Authored by accessibility.ts

Rule illustration; not an executed check. icon / icon.hidden-unless-labelled

<a href="/contact/"><svg aria-hidden="true">…</svg></a>
The link has no visible words or accessible name.
A decorative icon is correctly silent beside words, but using that silent fragment as the whole link leaves its action unnamed.

Rules

RuleWhyCheck
axe reports zero serious or critical issues on every page.The floor is non-negotiable.Automated: tests/site (axe)
Colour never carries meaning alone.Colour-blind readers must get the same message.Review: Accessibility owner: inspect each meaningful state for a shape or written equivalent in monochrome and forced colours; whole-system review remains unrun. tests/site/identity.spec.ts checks V4 state-badge visibility in forced colours. check-pages.ts checks composition and captions, not non-colour meaning.

API

No props.

Contract details

The full contract: identity, anatomy, variants, states, tokens, layout, motion, accessibility, content, tests

Identity

AspectValue
Idaccessibility
LayerFoundations
Categoryfoundation
OwnerSite system lead
Statusstable
Version1.0.0
Sourceapps/showcase/site/system/foundations/accessibility.ts (private repository; the contract and the render function are this one module)
VersionDateChange
1.0.02026-10-26Accessibility as one module: its markup moved out of the page builder (scripts/site) into the system.

Use when

  • Every element. Why: Accessibility is part of the definition of done.

Do not use when

  • Never waived. Why: Exceptions need a record with an expiry.

Anatomy

PartWhat it is
passportEach contract's a11y block
checksaxe in Playwright, check-brand contrast, Lighthouse

Made of: nothing (a base element).

Used in: pages directly.

Variants

VariantWhenWhy
light and darkEvery page, following the reader's setting.The same roles resolve to light or dark values, so no element chooses its own.

States

StateRendered or not applicable
defaultThe specimen.
hoverNot applicable: A foundation is not interactive.
focus-visibleNot applicable: Not focusable.
activeNot applicable: Not interactive.
disabledNot applicable: Nothing to disable.
loadingNot applicable: Values are built into the stylesheet.
emptyNot applicable: The build fails if a value is missing.
errorNot applicable: Unresolved values fail the brand gate, not the reader.
currentNot applicable: No current item.
visitedNot applicable: Not a link.
expandedNot applicable: Does not open.

Tokens

PartToken
--focusFocus ring
target44 px

Layout

AspectValue
breakpointsRequired review at 390, 768, 1024 and 1440 px; execution is not implied by this declaration; columns stack under 768 px; the wrap keeps a 16 px gutter on phones.
wrappingText wraps; nothing scrolls sideways.
textExpansionJapanese runs 20 to 40% longer; headings break between phrases (jaBreaks) and blocks grow downwards.

Spacing and rhythm

AspectValue
internalNot applicable: a foundation has no box of its own.
externalNot applicable.
rhythmApplies to every element that reads it.

Motion

AspectValue
NoneA foundation does not move.

Runtime and reuse

  1. Render-only element; mount any registered child enhancements separately. Preserve required Site CSS, fonts, responsive and locale rules from nativeElement.

Accessibility passport

AspectValue
roleNot rendered on the site; its specimen in the Library is a list
nameThe foundation's name
keyboardNot interactive.
focusNot focusable.
screenReaderThe specimen is a plain list of names and values.
contrastEvery text and ground pair in the palette is checked (check-brand).
targetNot a target.

Content

SlotLengthVoice
accessible names in consuming controlsThe Button, Icon or other consuming contract's label budgetName the action or destination in words. Preserve visible labels and programmatic names; a symbol or colour cannot replace them.
meaningful state textBandWord uses one of its four names; other states follow their owning contractState the meaning beside the mark. The accessibility specimen lists policy targets, not measured results for the current page.

Good: “Book a conversation (Button's visible action name)” · “Holding together (BandWord's word beside its dyed mark)”

Bad: “An arrow alone as a button name” · “A health state shown only by a coloured dot”

Japanese: Translate control names, state words and hidden text through their consuming component's existing Japanese source. Retain English technical identifiers and explicitly English output. Check names and reading order in Japanese; this policy specimen is not a locale API, an assistive-technology result or completed native review.

Icons and illustrations

None: this element uses no icon or illustration of its own.

Decisions and exceptions

  • None.

Usage

26 owned-class occurrences in built pages plus metadata-token references in built CSS (measured by npm run site:system).

No application mechanism is declared.

Current check result: not assessed by this report. Declarations and source-file presence do not establish executed enforcement or accepted coverage.

Tests

AspectValue
unittests/unit/site-system.test.ts: renders every do and don't example through the registry and checks the classes it owns
visualNot yet: there are no screenshot baselines; the Library page is checked for sideways scroll at 1440 px by tests/site/system.spec.ts
a11ytests/site/system.spec.ts: axe (0 serious or critical) on the element's Library page in light and dark
parityscripts/site/system/check.ts: Library examples are rendered by the same render function the site imports

Figma

not-yet: The Loom Site Figma library is the last stage of the plan; this element is not mapped yet.

Open in Storybook

Start with a conversation about your system.

We read your system, show you what we found, and agree with your team what to fix first.