Stockio

ARIA Roles Explained: When Native HTML Is Better

Learn when ARIA adds useful semantics, how roles and states work, and why native HTML should remain your starting point for accessible interactive components.

By Noor Haddad

Accessibility Specialist ·

On this page

ARIA changes how an interface is described to assistive technology. It does not automatically change how that interface behaves. Understanding that boundary prevents a common failure: controls that sound interactive but cannot actually be operated with a keyboard.

Start with the accessibility contract

Every interactive element makes promises about its name, purpose, current condition, and operation. A button promises activation; a checkbox promises a checked state. Native HTML supplies many of these promises together, including browser behavior that would otherwise need custom JavaScript.

During an audit, separate semantic problems from visual problems. Use the contrast checker to compare text and background colors, then inspect the accessibility tree to check names and roles. A passing color ratio cannot prove that a control has correct semantics, and correct ARIA cannot rescue unreadable text.

Begin with a small inventory: links, buttons, fields, disclosures, and composite widgets. Record what each element does before adding attributes. The broader WCAG interface guide provides context for combining these checks into a complete review rather than treating ARIA as a compliance shortcut.

Distinguish roles, states, and properties

A role identifies an element's kind. Examples include button, checkbox, dialog, and tab. Browsers already derive roles from many HTML elements. A real button normally needs no explicit button role, and a heading should usually be a heading element rather than a generic container with heading attributes.

States communicate changing conditions such as expanded, checked, selected, or busy. Properties describe information and relationships such as an accessible label or the element controlled by another element. The distinction is useful conceptually, although both are expressed with aria-prefixed attributes and some properties can also change.

An accessible name answers which control this is. Visible button text normally supplies that name. An accessible description supplies supplementary information, such as input instructions, without replacing the name. Do not combine every available naming attribute in the hope that more metadata is better; naming precedence can hide useful visible wording.

Read the WAI-ARIA specification when deciding whether a state is supported by a role. Attributes are not universally meaningful. For example, selected describes selection in particular widget patterns, not every item that happens to have a colored background.

Prefer browser behavior over recreated widgets

A generic container with a button role remains a generic container in important ways. You must make it focusable, implement appropriate keyboard activation, handle disabled behavior, and ensure that pointer and keyboard interactions produce the same result. A native button already handles Enter and Space activation.

Use anchors with real destinations for navigation and buttons for actions. Do not choose between them based on visual appearance: CSS can style either. Likewise, native checkboxes, selects, and disclosure elements often avoid substantial interaction code while retaining familiar behavior across browsers and input methods.

The ARIA Authoring Practices introduction explains why incorrect ARIA can be worse than none. Applying a role creates expectations; failing to implement those expectations actively misleads users. No ARIA is often better than bad ARIA, but missing semantics on a genuinely custom widget still needs a proper fix.

Avoid redundant attributes unless there is a documented compatibility reason. Do not override meaningful native semantics merely to silence an automated warning. When reviewing a component library, consult its interaction contract alongside its styling API; related implementation choices appear in the development collection.

Implement one truthful disclosure

A disclosure illustrates the right division of responsibility. HTML provides the button. JavaScript updates both the panel visibility and the expanded state. The relationship uses an actual, unique ID rather than a selector that might match several elements.

<button type="button" aria-expanded="false" aria-controls="shipping">
Shipping details
</button>
<div id="shipping" hidden>
Standard shipping takes three to five business days.
</div>
<script>
const trigger = document.querySelector('[aria-controls="shipping"]');
const panel = document.getElementById('shipping');
trigger.addEventListener('click', () => {
  const expanded = trigger.getAttribute('aria-expanded') === 'true';
  trigger.setAttribute('aria-expanded', String(!expanded));
  panel.hidden = expanded;
});
</script>

This example does not need custom key handlers because the native button generates click events for normal keyboard activation. It also does not need a live region: expanded state and discoverable panel content are the relevant communication. Adding announcements indiscriminately can make a simple interaction unnecessarily noisy.

Treat state synchronization as an invariant. If application code closes the panel after navigation, it must also update expanded. If a framework renders the component, derive both attributes from the same state value rather than maintaining separate competing sources of truth.

For production, decide what happens before JavaScript loads. One option is to render content visible and progressively enhance the disclosure. Another is to use native details and summary when their behavior fits. A script-dependent hidden panel otherwise makes its information unavailable when initialization fails.

Test semantics and interaction together

Use browser developer tools to inspect the computed role, name, and state. Then test with the keyboard, not just the accessibility tree. Tab should reach the trigger in a sensible sequence; Enter and Space should toggle it; focus should remain visible and should not jump unexpectedly into the panel.

Test at least one screen reader and browser combination used by your audience. Listen for the control's name and expanded state. The exact wording varies, so verify meaning rather than requiring an identical spoken sentence on every platform. Consult MDN's ARIA overview for implementation references and cautions.

Be especially careful with aria-hidden. It removes content from the accessibility tree but does not stop keyboard focus. Never hide a focusable control, or an ancestor containing focusable descendants, while leaving it operable. Use appropriate visibility or inert behavior when the interaction genuinely needs to be unavailable.

Make the review reproducible. Record the browser, assistive technology, steps, expected result, and actual result. Automated checks can identify invalid attributes or missing names, but manual testing is needed to judge whether a label makes sense and whether the complete workflow remains usable after state changes.

Key takeaways

  • Choose native elements before recreating their semantics and interaction.
  • Use roles for purpose, states for condition, and names for identification.
  • Keep rendered visibility and ARIA state synchronized from one source.
  • Treat keyboard support as a separate implementation responsibility.
  • Check the accessibility tree and complete real screen reader workflows.
Featured sponsor

Reach designers & developers at work

Put your product next to the tools people use every day. One sponsor per placement, no tracking pixels.

Become a sponsor

Keep reading

Related articles

More in Accessibility
Accessibility

10 Best Accessibility Courses and Learning Resources

Learn practical web accessibility through standards, tutorials, videos, and real interface examples. These ten trusted resources help beginners and working teams build skills and choose a useful next step.

Includes: Contrast checkerNoor HaddadNoor Haddad
Accessibility

10 Best Accessibility Browser Extensions for Testing

Compare ten browser add-ons for spotting accessibility issues while you browse or build, from automated page scans to heading and contrast checks, plus advice for turning findings into fixes.

Includes: Contrast checkerTheo OkaforTheo Okafor
Accessibility

12 Best Accessibility Testing Tools for Websites

Compare twelve practical accessibility testing tools, from browser extensions and automated checks to screen readers and code libraries, and learn how to choose a sensible mix for your site.

Includes: Contrast checkerNoor HaddadNoor Haddad
Accessibility

Accessible Tabs: Build a Keyboard-Friendly Tabs Component

Implement accessible tabs with correct roles, roving tabindex, manual activation, and panel relationships, then test keyboard behavior and progressive enhancement.

Includes: Contrast checkerTheo OkaforTheo Okafor
Accessibility

Automated Accessibility Testing With axe and Lighthouse

Combine axe state-based checks with Lighthouse page audits, triage actionable findings, and add manual verification without mistaking a clean report for WCAG conformance.

Includes: Contrast checkerNoor HaddadNoor Haddad
Accessibility

How to Do an Accessibility Audit and Write the Report

Scope an accessibility audit, combine automated and manual testing, and write evidence-based findings that developers can reproduce, prioritize, fix, and retest.

Includes: Contrast checkerTheo OkaforTheo Okafor