J5.10.3accessibility state synchronizationdesignresearch

State changes must be written to the accessibility tree, not only to appearance

Aliases: aria-expanded · aria-checked · aria-disabled · widget state

What it is

The chevron rotated, the background went grey, a tick appeared — that is still paint. For assistive technology to know “expanded, disabled, checked,” the matching properties have to be written into the accessibility tree: accessibility state synchronization. aria-expanded, aria-checked, aria-disabled, aria-pressed, aria-selected, and a native control’s own disabled / checked are state on the tree. Changing a class and CSS leaves the tree on the previous beat.

This is not “shout when a region of the page is replaced.” That is announcement. This asks, of the same widget, which state it is in now, and whether the tree followed the appearance.

Why it happens

When focus lands on a control, or when a state property changes, the reader speaks the state: “expanded,” “not checked,” “dimmed, unavailable.” It reads attributes on the tree node, not rotation angles. The visual layer can animate a collapse while the tree still says expanded=true, and speech will keep saying expanded after the motion ends. The inverse also holds: script flips aria-expanded and leaves the picture alone, and sighted and listening users disagree.

The second layer is timing. State has to hit the tree on the same beat as the user action, not on transitionend. Readers subscribe to property-change events; they do not sample every frame. One beat late, the user has already pressed again, heard the old state, and built the next action on a false premise. Disabled is the usual “looks grey” cheat: CSS blocks pointer events, the tree remains focusable and activatable.

Studying it

Build an accordion or a custom checkbox in three cells: appearance only; ARIA only; both. After each toggle, have NVDA or VoiceOver speak the control immediately, and read the state properties in the inspector. Add a cell that writes state in the animation-end callback, and measure what a double-press hears.

Independent variables: when state is written (synchronous / after animation / never), native versus custom. Dependent variables: state words in speech, inspector attributes, whether the second keypress acts on the state the user thought they were in.

Where it stops holding

Native <details> and <input type="checkbox"> have open/checked written by the user agent; authors need not, and should not, duplicate aria-expanded. A static “done” badge that is not a widget has no state change to sync and should not be faked as aria-pressed. Busy and loading transients sit closer to announcement than to widget state; stuffing them into aria-busy without moving focus can mean they are never heard. In remote collaboration, “someone else selected this” can turn sync into noise and needs throttling — but not throttling of the user’s own click.

Applying it

  • On every collapse, check, disable, or toggle, write the tree property in the same function that changes appearance; do not put it in an animation callback.
  • Disable with real disabled or aria-disabled and take the control out of the tab order or announce it as unavailable; do not only add a grey class.
  • Custom switches must keep aria-checked or aria-pressed and the visible on/off on the same piece of data.
  • How to check: cover the display, operate each togglable control once, and listen for the state word to flip; then watch the inspector to see the attribute change on the click, not later. Paint moved and the attribute did not, or the attribute moved and speech still names the old state, means sync was done halfway.

Related

  • Same group: J5.10.1 Accessible names are computed from multiple sources in a fixed, overridable order · J5.10.2 Visible text and the computed accessible name can disagree · J5.10.4 Custom widgets often ship a role but omit the matching state properties
  • Nearby: J5.02 Accessibility tree and roles · J5.12 Live regions and dynamic announcements
  • Search terms: accessibility state synchronization · aria-expanded · aria-checked

Cards in the same group

Quick Actions

Share

Share this page

ios_share

https://hci.top/en/handbook/J5.10.3