ARIA is one of the most powerful accessibility tools available to web developers. It is also one of the easiest ways to make an interface worse while feeling like you made it better.

That sounds harsh, but ARIA deserves a little caution. It is not a magic accessibility layer. It is not a shortcut around semantic HTML. It is not a way to sprinkle screen reader friendliness onto a custom component after the real interface has already been designed.

ARIA helps describe interface meaning to assistive technology. It can tell a screen reader that something is a button, a tab, a dialog, a menu item, an expanded section, a selected option, or a progress indicator. It can connect a control to a label, a description, or a related region.

But ARIA mostly describes. It does not automatically make a custom component behave correctly. If you build a fake button out of a div and add role="button" , you have not built a button. You have made an element announce itself as a button. You still need keyboard focus, keyboard activation, disabled state behaviour, focus styles, accessible naming, and all the boring behaviour native buttons already provide for free.

The first rule of ARIA

If a native HTML element already provides the semantics and behaviour you need, use the native element. A real button , a , input , select , or dialog is usually a better starting point than a generic element with ARIA added later.

What ARIA actually does

ARIA stands for Accessible Rich Internet Applications. In practical web development terms, it gives developers a way to add accessibility information to markup when native HTML cannot fully describe a custom interface.

ARIA communicates through three broad kinds of information:

  • Roles , which describe what kind of thing an element is.
  • States , which describe a condition that can change.
  • Properties , which describe labels, relationships, or other supporting information.

A role might say that an element is a button , tab , dialog , progressbar , switch , or menuitem . A state might say that something is aria-expanded="true" , aria-selected="false" , or aria-checked="mixed" . A property might connect an element to a label with aria-labelledby , provide a text label with aria-label , or describe extra help text with aria-describedby .

This information becomes part of the accessibility tree, which is the version of the page exposed to assistive technology. That tree is not the same thing as the DOM, and it is not the same thing as the visual interface. It is the non-visual representation a screen reader, voice control system, or other assistive tool may use to understand what is on the page.

ARIA changes meaning, not behaviour

This is the point that causes a lot of trouble: ARIA can change how an element is exposed to assistive technology, but it usually does not add the behaviour users expect from that role.

If an element has role="button" , assistive technology may announce it as a button. But the browser does not automatically make it work like a native button. You still need to make sure it can receive keyboard focus. You still need to make sure Enter and Space activate it in the expected way. You still need to make sure focus is visible. You still need to make sure the name of the button explains the action.

That is why native HTML matters so much. Native controls bundle semantics and behaviour together. A button is announced as a button, receives focus, responds to keyboard activation, participates in forms where appropriate, and gives the browser and assistive technology a shared understanding of what it is.

ARIA asks you to rebuild some of that contract yourself. Sometimes that is necessary. Often it is not.

Accessible names are not optional

Many ARIA failures are really naming failures. A control can have the correct role and still be unusable if it has no accessible name.

An accessible name is the name assistive technology can announce for an element. For a visible text button, the accessible name often comes from the button text:

<button>Save changes</button>

That button has a useful name because the visible text is also available to assistive technology.

Icon-only buttons are different. A button that contains only an icon may look obvious to a sighted user, but a screen reader may only announce it as “button” unless you provide a name:

<button aria-label="Close dialog">
  <svg aria-hidden="true">...</svg>
</button>

This can be valid, but it should not become an excuse to hide meaning from the visible interface. If visible text is practical, visible text is often better. It helps more people, including sighted users, voice control users, new users, distracted users, and future-you debugging a component at an unreasonable hour.

ARIA must match the visual interface

ARIA is dangerous when it lies.

If a menu is visually collapsed but exposed as expanded, users may hear the wrong state. If a tab looks selected but does not expose aria-selected="true" , screen reader users may not know which panel is active. If a dialog opens visually but focus remains behind it, keyboard and screen reader users may be left interacting with the page underneath.

Good ARIA is not just about adding attributes. It is about keeping the non-visual interface synchronized with the visual interface.

That means state needs to update when the UI changes:

  • aria-expanded should change when disclosure content opens or closes.
  • aria-selected should reflect the selected tab, option, or item.
  • aria-checked should reflect the current state of checkboxes, switches, and similar controls.
  • Dialogs should have accessible names and sensible focus management.
  • Hidden content should not contain focusable controls that users can tab into silently.

If those states drift away from the real interface, ARIA stops being context and starts being misinformation.

Some ARIA relationships are structural

ARIA also creates relationships between elements. This is useful, but it adds another place where mistakes can hide.

Attributes such as aria-labelledby , aria-describedby , aria-controls , and aria-owns often rely on element IDs. That means the IDs need to exist, they need to be unique, and they need to point to the right elements.

This is where reusable components can become little accessibility goblin factories. A component might work perfectly when rendered once. Then it is rendered six times on the same page and suddenly the generated IDs are duplicated. A label points to the wrong description. A dialog references a heading from another dialog. A control announces information from its neighbour because the relationship looked correct in a single example but failed in real use.

Duplicate IDs are not only an HTML cleanliness problem. When ARIA depends on IDs, duplicate IDs can break the meaning of the interface.

ARIA patterns include keyboard contracts

Complex ARIA widgets often require keyboard behaviour that matches user expectations. This is where many custom components fail.

A tab interface is not only a row of buttons with role="tab" . It is a pattern. The selected tab needs to be clear. The active panel needs to be connected. Keyboard users need a predictable way to move between tabs. Focus should not wander into hidden panels. The DOM, visual state, ARIA state, and keyboard behaviour all need to tell the same story.

The same is true for menus, comboboxes, tree views, dialogs, accordions, switches, and other interactive patterns. If you use a custom ARIA pattern, you inherit the responsibility for the full pattern, not only the role names.

No ARIA is often better than bad ARIA

Bad ARIA can misrepresent the interface to assistive technology. That is worse than leaving a generic element generic, because it gives users confidence that a control should behave in a certain way while the actual behaviour does something else.

Common ARIA mistakes

Most ARIA problems are not exotic. They are ordinary implementation mistakes repeated across components, templates, and design systems.

  • Adding role="button" to an element that cannot be reached or activated with the keyboard.
  • Creating icon-only buttons without accessible names.
  • Using aria-label that does not match the visible label.
  • Leaving aria-expanded , aria-selected , or aria-checked stuck in the wrong state.
  • Hiding content with aria-hidden="true" while leaving focusable controls inside it.
  • Referencing IDs that do not exist.
  • Reusing components that generate duplicate IDs.
  • Adding ARIA roles where native HTML would have worked better.
  • Using ARIA to change semantics without implementing the expected keyboard behaviour.

These are not small details to the people affected by them. They determine whether an interface is understandable, predictable, and usable.

How Siteimp helps inspect ARIA

Siteimp does not try to replace manual accessibility testing. It cannot tell you whether every workflow feels right with a screen reader. It cannot know whether the words in your labels are the best words for your users. It cannot replace testing with real people.

What Siteimp can do is expose evidence that makes review easier.

Siteimp’s accessibility checks include many ARIA-related findings, such as invalid ARIA attributes, invalid attribute values, invalid roles, required attributes, prohibited attributes, required parent and child roles, accessible names for command elements, dialog names, input names, toggle names, hidden focusable content, duplicate ARIA IDs, and role compatibility problems.

That matters because ARIA issues often live in shared components. If a button component, dialog component, tab component, menu, drawer, or form control has a problem, it may repeat across many pages. Finding the pattern is the first step toward fixing the system.

The useful question is not only “did this page pass?” The better question is often:

  • Is this a page content problem?
  • Is this a shared component problem?
  • Is this a design system or theme problem?
  • Is this a state management problem?
  • Is this a keyboard behaviour problem?

ARIA becomes much easier to fix when you can see where the failure likely belongs.

A practical ARIA review process

When reviewing ARIA, I like to start with a few simple questions:

  1. Can this be native HTML? If a native element already provides the right meaning and behaviour, use it.

  2. Does the element have the right role? If a custom role is needed, make sure the role matches what the control actually does.

  3. Does it have a useful accessible name? A control without a name is a mystery button with better paperwork.

  4. Do states update when the interface changes? Expanded, selected, checked, disabled, and hidden states need to match reality.

  5. Do relationships point to the right elements? Check IDs, labels, descriptions, controls, and ownership relationships.

  6. Does keyboard behaviour match the pattern? If the role implies a known interaction pattern, the keyboard behaviour needs to support it.

  7. Have you tested it with a screen reader? Automated checks can catch many mistakes, but they cannot tell you whether the interaction actually feels coherent.

Conclusion

ARIA is not a shortcut. It is a contract.

When you add ARIA, you are telling assistive technology what something is, how it is named, what state it is in, and how it relates to other parts of the interface. If that information is accurate, synchronized, and backed by correct keyboard behaviour, ARIA can make complex interfaces much easier to use.

If that information is wrong, ARIA can turn an already difficult interface into a non-visual haunted house.

Start with native HTML. Add ARIA only when it is needed. Keep it synchronized with the interface. Test the result with the keyboard and a screen reader. That is slower than sprinkling attributes into markup and declaring victory, but it is also the difference between accessibility theater and accessibility work.