Composition Accessibility Defect
also called Assembled-Page Accessibility Defect, Integration-Level A11y Failure
An accessibility failure that exists only in the assembled page - focus order, landmark duplication, heading structure, announcement rate - and that every individually conformant component can pass its own checks while producing.
A design system ships forty components. Each has unit tests and an automated accessibility check, and all of them pass. An external audit then fails the checkout flow on focus order and on announcements, and the team's first reaction is that the tooling must be broken.
The tooling is fine. Accessibility conformance is defined over pages and flows, not over components. Several of the criteria describe relationships that do not exist until things are assembled: the order focus moves in, whether a landmark appears once, whether heading levels form a sensible outline, whether a change is announced at a rate a person can absorb. A component cannot pass or fail those on its own, so a component-level check is silent about them, and silence reads as success.
This is the accessibility form of a general problem: a green suite at one altitude says nothing about the altitude above it, and the strongest component-level programme makes the gap more persuasive rather than less.
Why it matters
Component checks are genuinely valuable and they hit a ceiling. Automated tooling can decide only a minority of the criteria at all; within that minority, component-scoped runs cover the properties of individual widgets and almost nothing about their arrangement. A pass rate on components is an input metric, and the audit measures the output.
The consequences are not marginal. A keyboard user who cannot reach the checkout button cannot buy anything, and the legal exposure attaches to the flow, not to the library. The defects also cluster in two places - route changes and asynchronous updates - which makes them cheap to hunt once you know where to look.
Implementation patterns
- Assert focus management where it is decided. On every route change, move focus to the new view's heading. Putting that assertion in the router covers every page at once; putting it in page tests means writing it once per page and forgetting it on the next one.
- Run a small set of assembled journeys. Five to ten keyboard-only and screen-reader-driven paths through the critical flows, once per release. Because the defects cluster, a small set finds most of them.
- Rate-limit live regions by design. Assistive technology serialises announcements: each must finish being spoken before the next starts. A polite region updated every two seconds with a phrase that takes several seconds to speak enqueues faster than it drains, and the user hears stale positions and nothing else. Announce on threshold crossings and leave the changing value in an ordinary element.
- Assert landmark and heading uniqueness at the layout level, where composition happens, rather than in each component.
- Publish a composition contract with the design system: which component owns focus on open and close, which declares a landmark, what heading level it assumes. Composition defects are usually two correct components making the same reasonable assumption.
Industry example
High-demand ticketing platforms make the live-region case concrete. A waiting-room page of the kind a large ticketing platform in the mould of Ticketmaster puts in front of an on-sale shows a continuously decreasing queue position, and the obvious implementation announces every update through a polite live region. It passes every automated check, because the markup is correct and the update rate is a design decision no checker evaluates. The experience is unusable: the announcement queue never drains, and the seat-hold timer - the one message with a deadline attached - never gets spoken.
Failure scenarios
- Focus stranded after a route change, so the next Tab starts from the top of a view that no longer exists.
- Two main landmarks because a page shell and an embedded widget each declare one correctly.
- A heading outline that jumps from h1 to h4 because each component chose a locally sensible level.
- A modal that traps focus correctly and returns it to the wrong element, or to nothing, on close.
- Error summaries that render without being announced, so the form appears to do nothing on submit.
- A virtualised list that recycles DOM nodes and moves focus out from under the user as they scroll.
Trade-offs
Assembled journeys are slower, need real or emulated assistive technology, and are more prone to flakiness than component checks - they are end-to-end tests with all the properties that implies. The answer is not to have many of them. Keep the component checks doing the volume work, and spend a deliberately small budget at the assembled level where nothing else can see. Replacing component checks with journeys would multiply the finding count and the cost at the same time.
When not to use it
A single-page product with one form and no client-side routing does not need a router assertion or a journey suite; the component checks plus one manual keyboard pass cover the surface. Below roughly a handful of flows, the audit and a person with a keyboard are cheaper and better than automation. The practice earns its cost when many products share one library - which is also exactly when the component pass rate becomes most convincing and most misleading.
Interview question
Q: Your design system reports 100% accessibility compliance on every component and an external audit just failed your checkout on focus order and announcements. Explain to the delivery director what happened, and tell me what you would add without slowing the release train.
What a strong answer covers: conformance is a property of pages and flows, so component checks are structurally silent on relationships · name the specific classes - focus on route change, duplicated landmarks, heading outline, announcement rate · one router-level focus assertion covering the whole application · five to ten assembled journeys per release rather than a large suite · the live-region serialisation mechanism and the threshold-crossing fix · keep the component checks and be explicit that the pass rate is an input metric.
Quick check
Quiz: Which accessibility defect class can no component-level check detect, however thorough? Relationships between components - focus order across views, landmark duplication, heading structure and announcement rate.
Flashcard: Where do composition accessibility defects cluster? - At route changes and asynchronous updates, which is why one focus assertion in the router plus a handful of assembled journeys finds most of them.