Skip to main content
WCAGrules
Quick navigation

ARIA

States and properties

An ARIA role says what something is. A state or property says what condition it is in, or how it was set up. There are 9 states and 37 properties still in use, and ARIA itself says the line between the two matters far less than the names suggest. What matters is whether the value is still true by the time somebody reads it.

These are not rare. In February 2026 the top million home pages carried an average of 133 ARIA attributes each, up 27% in a year, and 23.3 of those were aria-hidden set to true. Every one of those is a decision to take something out of the accessibility tree, and on an element still sitting in the tab order it hides a control a keyboard user can land on anyway.

The state versus property line matters less than you think

The split reads like it should be load bearing and it is not. ARIA says in its own text that the difference is of little consequence to most authors, and it calls both of them attributes wherever it can. The rough idea is that a state changes while somebody uses the control and a property is set up front. Pressed, expanded, checked and selected are states. A label, or whether a field is required, is a property.

Then the specification says the frequency of change is not a rule, and its own list proves the point. A slider's current value moves every time somebody drags it and it is a property. The active option in a listbox changes on every arrow press and it is a property. So the line is worth knowing because the specification draws it, not because it tells you when to update anything.

The failure this section is really about sits on both sides of the line. An attribute set once and never updated is worse than no attribute at all, because now it is actively lying. A menu button carrying aria-expanded="false" that never flips to true tells a screen reader user the menu is shut while they are sitting there with it open.

States (9)

These change as someone uses the control, and your code has to keep them current.

  • aria-busytrue/false

    Says a region is still being updated, so wait before announcing it.

  • aria-checkedtristate

    Whether a checkbox, radio or switch is on, off, or partly on.

  • aria-currenttoken

    Marks the one item in a set that represents the here and now, such as the current page in a nav.

  • aria-disabledtrue/false

    Says a control is present but not available. Unlike the disabled attribute, it stays focusable, so people can still find out it is there.

  • aria-expandedtrue/false/undefined

    Whether the thing this control opens is currently open.

  • aria-hiddentrue/false/undefined

    Removes an element from the accessibility tree while leaving it on screen.

  • aria-invalidtoken

    Says a field's value has failed validation.

  • aria-pressedtristate

    Whether a toggle button is currently pressed. This is what makes a button a toggle.

  • aria-selectedtrue/false/undefined

    Whether an option, tab or row is the chosen one.

Properties (37)

Mostly configuration, set when the element is built. Several of these move constantly all the same. A slider's current value and a listbox's active option are both properties, and both change on every keypress.

  • aria-activedescendantID reference

    Points at the item inside a composite widget that is currently active, when focus stays on the container.

  • aria-atomictrue/false

    Whether an update should be read whole, or only the part that changed.

  • aria-autocompletetoken

    How a text field predicts what you are typing.

  • aria-colcountinteger

    How many columns a table really has, when only some are rendered.

  • aria-colindexinteger

    Which column a cell is in, counting from the real table rather than what is shown.

  • aria-colspaninteger

    How many columns a cell spans, when the markup cannot say so itself.

  • aria-controlsID reference list

    Points at what this control operates. A combobox has to say what it opens.

  • aria-describedbyID reference list

    Points at further description, read after the name. Hints and error text usually go here.

  • aria-detailsID reference

    Points at richer explanation elsewhere in the page, which people can navigate to rather than have read out.

  • aria-errormessageID reference

    Points at the message explaining why this field is invalid. Only meaningful while aria-invalid is set.

  • aria-flowtoID reference list

    Overrides reading order by pointing at what should be read next. Rarely the right answer.

  • aria-haspopuptoken

    Says this control opens something, and what kind of thing it opens. A menu, a dialog, a listbox.

  • aria-keyshortcutsstring

    Lists the keyboard shortcuts that activate this control, so they can be announced and checked for clashes.

  • aria-labelstring

    Gives an element a name as a plain string. Use it when there is no visible text to point at.

  • aria-labelledbyID reference list

    Names an element by pointing at visible text already on the page. Preferred over aria-label, because the name then matches what people see.

  • aria-levelinteger

    The depth of a heading or a tree item, counting from one.

  • aria-livetoken

    Marks a region whose updates should be announced, and how urgently.

  • aria-modaltrue/false

    Says everything behind this dialog is unavailable, so a screen reader stops at its edge.

  • aria-multilinetrue/false

    Whether a text field takes more than one line, which changes what Enter does.

  • aria-multiselectabletrue/false

    Whether more than one option can be chosen at once.

  • aria-orientationtoken

    Whether a widget runs horizontally or vertically, which decides which arrow keys move through it.

  • aria-ownsID reference list

    Claims elements as children when the markup cannot nest them. A last resort, and easy to get wrong.

  • aria-placeholderstring

    A hint shown in an empty field. It is not a label and does not replace one.

  • aria-posinsetinteger

    Which position this item holds in its set, when the markup does not contain the whole set.

  • aria-readonlytrue/false

    The value can be read but not changed. Unlike disabled, it is still part of the form.

  • aria-relevanttoken list

    Which kinds of change in a live region are worth announcing.

  • aria-requiredtrue/false

    Says a field has to be filled in before the form can be submitted.

  • aria-roledescriptionstring

    Replaces the spoken name of the role with your own wording. Use sparingly, and never to rename a standard control.

  • aria-rowcountinteger

    How many rows the table really has, when only some are rendered.

  • aria-rowindexinteger

    Which row this is, counting from the real table.

  • aria-rowspaninteger

    How many rows a cell spans, when the markup cannot say so.

  • aria-setsizeinteger

    How many items the set really holds, when only some are in the markup. Together with aria-posinset this is what makes an infinite list announce as 5 of 200.

  • aria-sorttoken

    Which way a table column is currently sorted.

  • aria-valuemaxnumber

    The highest value a range control accepts.

  • aria-valueminnumber

    The lowest value a range control accepts.

  • aria-valuenownumber

    The value a range control currently holds.

  • aria-valuetextstring

    A readable version of the current value, for when the number is not what people say. Large, rather than 3.

Usable anywhere (15)

These are global, meaning they work on any role, which is why no individual role lists them. Three carry an exception worth knowing. aria-label, aria-labelledby and aria-roledescription are forbidden on eleven roles that have no name of their own, paragraphs and generic elements among them. A bare div is one of those generic elements, so naming one does nothing at all, and that is one of the most common wasted fixes there is.

  • aria-atomictrue/false

    Whether an update should be read whole, or only the part that changed.

  • aria-busytrue/false

    Says a region is still being updated, so wait before announcing it.

  • aria-controlsID reference list

    Points at what this control operates. A combobox has to say what it opens.

  • aria-currenttoken

    Marks the one item in a set that represents the here and now, such as the current page in a nav.

  • aria-describedbyID reference list

    Points at further description, read after the name. Hints and error text usually go here.

  • aria-detailsID reference

    Points at richer explanation elsewhere in the page, which people can navigate to rather than have read out.

  • aria-flowtoID reference list

    Overrides reading order by pointing at what should be read next. Rarely the right answer.

  • aria-hiddentrue/false/undefined

    Removes an element from the accessibility tree while leaving it on screen.

  • aria-keyshortcutsstring

    Lists the keyboard shortcuts that activate this control, so they can be announced and checked for clashes.

  • aria-labelstring

    Gives an element a name as a plain string. Use it when there is no visible text to point at.

  • aria-labelledbyID reference list

    Names an element by pointing at visible text already on the page. Preferred over aria-label, because the name then matches what people see.

  • aria-livetoken

    Marks a region whose updates should be announced, and how urgently.

  • aria-ownsID reference list

    Claims elements as children when the markup cannot nest them. A last resort, and easy to get wrong.

  • aria-relevanttoken list

    Which kinds of change in a live region are worth announcing.

  • aria-roledescriptionstring

    Replaces the spoken name of the role with your own wording. Use sparingly, and never to rename a standard control.

Deprecated

Both belong to a drag-and-drop model ARIA has since dropped. They are listed because you will meet them in older code, and because deprecated is not the same as dead. ARIA still encourages browsers to support them, so the honest advice is to stop writing them rather than to assume the ones already there do nothing.

  • aria-dropeffecttoken list

    Marked what a drop would do to the target, in the drag-and-drop model ARIA deprecated in version 1.1. Here because you will meet it in older code.

  • aria-grabbedtrue/false/undefined

    Marked the item being dragged, in the drag-and-drop model ARIA deprecated in version 1.1. Here because you will meet it in older code.

The roles that require one of these

Eleven roles are not properly described until one of these is present. A checkbox needs aria-checked. A combobox needs aria-expanded and aria-controls. One of the eleven is conditional, since a separator needs a value only when it is focusable, and a plain dividing line needs nothing. Every ARIA role sets out which attributes it expects.

Go somewhere useful

Find tools, resources and your workspace.

29 destinations