Lesson 17 · Part 4 · States

States and widget properties

A state is a fact about a control that can change while the page is open: checked, expanded, invalid, at 40 percent. ARIA attributes report that fact. They never cause it. Your script updates the picture and the attribute together.

In one minute

In plain words

A state is the label on a door that says "Open" or "Closed". If the door opens and the sign still says "Closed", people walk away. ARIA states are that sign for people who cannot see the door. The attribute never opens the door: you do, and then you flip the sign.

1. See the tree change: pressed, expanded, value

Here are three widgets side by side. Use them with the mouse or the keyboard. The panel below the controls shows what the accessibility tree holds and what a screen reader would say after each change.

Step 1. Press Pin, press Details, drag Volume (or use the arrow keys).

Live state of each control
ControlAttribute in the tree

aria-controls links the button to the panel it shows. Support is uneven, so never rely on it alone: aria-expanded is what matters. The range input is native, so its value is already exposed. aria-valuetext only improves how the number is spoken.

2. Three states for one checkbox: true, false, mixed

A parent checkbox for a group is mixed when only some children are checked. A native checkbox does this with the script property indeterminate. A custom one uses aria-checked="mixed". Tick the children and watch the parent.

Step 2. Tick some toppings, or click the parent (or press Space on it).


          

Do not put aria-checked on a native <input type="checkbox">. The browser already exposes the state, and a second value can disagree with it. aria-pressed is for toggle buttons (Pin above). It can be mixed too, but it is not a checkbox.

3. Disabled, read-only, and what keyboard users can reach

"Cannot change" has three meanings, and each behaves differently for a keyboard user. Choose one and press Tab to see if you can land on it.

Compare
FeatureResult

Prefer a native disabled when there is nothing to explain. Prefer aria-disabled when focus should stay so the reason can be read. With aria-disabled your handler must check the flag, because the browser will not block the click.

4. Invalid fields and their error message

aria-invalid="true" says "this value is wrong". It does not say why. Link the explanation with aria-errormessage or aria-describedby. Type something in the field (try hello), press Check, and switch between the three versions.


          

aria-errormessage is meant for exactly this, but screen reader support has been uneven, so many teams use aria-describedby too, or instead. Show the error text visibly and never rely on the red colour alone (WCAG 1.4.1, 3.3.1). Use aria-invalid="grammar" or "spelling" only in editors, not for a missing email.

5. Range values: a number or a word?

A slider needs aria-valuenow, aria-valuemin and aria-valuemax. When the bare number would be unhelpful ("3"), add aria-valuetext with the word you want spoken ("Wednesday"). This slider is built from a div so you can see every part. Focus it and press the arrow keys, Home or End.

Delivery day

          

Keep aria-valuenow inside the min and max. For an indeterminate progress bar, omit aria-valuenow rather than invent a percentage. If you set aria-valuetext, update it every time aria-valuenow changes.

6. Every state at a glance

Filter by family or type a word ("popup", "table", "number"). Each card says what values it takes, where it goes, what it does, and the usual trap.

Common mistakes

Common ARIA state mistakes
You seeWhy it is a problemFix
aria-checked on a native checkboxTwo sources of truth that can disagree.Remove it. Use checked or indeterminate.
Class changes, attribute does notScreen reader hears the old state.Set the attribute in the same function.
aria-pressed on a button that does not stay onAnnounces "not pressed" forever.Remove it.
aria-selected used for "current page"Wrong meaning.Use aria-current="page".
aria-invalid with no messageUser knows it is wrong, not why.Add visible text and link it.
aria-required relied on for validationIt only labels. It enforces nothing.Use required or a submit handler.
aria-valuenow outside min and maxMeaningless readout.Clamp the value.
Try it yourself
  1. Press Pin and Details with the keyboard (Tab, then Space). In devtools, watch pressed and expanded flip in the Accessibility panel.
  2. In lab 5, choose "Number only", then "With aria-valuetext". Which would you rather hear?
  3. In the card reference, search "popup". Which attribute announces that a menu is coming, and what does it never do?

Remember

Edit this example in the playground