DEV Community

Cover image for 99% of Developers Don’t Know These ARIA Attributes Exist
Muhammad Usman
Muhammad Usman

Posted on • Originally published at pixicstudio.Medium

99% of Developers Don’t Know These ARIA Attributes Exist

Before you go any further, I want you to support my original content:

Read the full story where it was first published

The Only ARIA Attributes Guide You’ll Ever Need in 2025

Accessibility is no longer optional, and honestly, the tools we have now made it easier than ever to build websites that work for everyone. ARIA attributes are at the heart of this, and they’re way more powerful than most developers realize.

So in this article, I’m going to walk you through every single ARIA attribute that exists. Not just the popular ones, I mean the complete, exhaustive list. These aren’t obscure specs gathering dust in documentation. These are practical tools that solve real problems when you’re building modern web applications.

Before we go any further, here is the link to CodePen with practical examples:

What Exactly Are ARIA Attributes?

ARIA stands for Accessible Rich Internet Applications. At its core, ARIA gives you a way to communicate with assistive technologies like screen readers. When you build a custom dropdown or a fancy modal, your code knows what it is, but a screen reader doesn’t. ARIA fill that gap.

Think of it this way, you create a beautiful tabbed interface using divs and CSS. Visually, it’s perfect, but someone using a screen reader has no idea those are tabs. Add the right ARIA attributes, and suddenly that screen reader understands the entire interaction pattern.

Why This Actually Matters

Over a billion people worldwide have some form of disability, that is approximately 15–16% of the global population. Many rely on screen readers, voice control, keyboard navigation, or other assistive technologies just to use the web. Without proper ARIA implementation, your site might look amazing but be completely unusable to them.

Accessibility isn’t just about compliance or avoiding lawsuits (though those are real concerns). Accessible websites are better websites. They’re more semantic, easier to navigate with keyboards, better structured, and often perform better in search engines as well.

The First Rule of ARIA

Before we go through deeply into this massive list, you need to know this, semantic HTML always comes first.

Don’t use <div role="button"> when <button> exists. Don't reinvent the wheel with ARIA when HTML already does the job. Native elements come with built-in accessibility, keyboard support, and expected behaviors. ARIA is for filling the gaps when HTML falls short.

Every ARIA Attribute That Exists

Alright, here’s the complete collection. I’ve grouped them by purpose so you can actually understand when and why you’d reach for each one.

Roles: Defining What Things Are

Roles tell assistive tech exactly what type of element they’re dealing with.

Landmark Roles

These define major sections of your page.

  • **role="banner"** Your main header area
  • **role="navigation"** Any navigation menu
  • **role="main"** The primary content
  • **role="complementary"** Supporting content like sidebars
  • **role="contentinfo"** Footer content
  • **role="search"** Search regions
  • **role="form"** Form areas
  • **role="region"** Important sections worth identifying

Document Structure Roles

These describe how your content is organized.

  • **role="article"** Self-contained composition
  • **role="document"** Document content
  • **role="feed"** Scrollable list of articles (like social media feeds)
  • **role="figure"** Images, diagrams, code snippets
  • **role="img"** Image containers
  • **role="list"** Lists of items
  • **role="listitem"** Individual list items
  • **role="math"** Mathematical notation
  • **role="none"**** or `role="presentation"**` Strips semantic meaning
  • **role="note"** Footnotes or side notes
  • **role="table"** Tabular data
  • **role="row"** Table rows
  • **role="rowgroup"** Groups of rows (thead, tbody, tfoot)
  • **role="cell"** Table cells
  • **role="columnheader"** Column headers
  • **role="rowheader"** Row headers
  • **role="separator"** Visual dividers
  • **role="toolbar"** Toolbar with controls
  • **role="tooltip"** Contextual popup info

Widget Roles

For all your interactive components.

  • **role="button"** Buttons
  • **role="checkbox"** Checkboxes
  • **role="radio"** Radio buttons
  • **role="textbox"** Text inputs
  • **role="searchbox"** Search inputs
  • **role="switch"** Toggle switches
  • **role="slider"** Range sliders
  • **role="spinbutton"** Number spinners
  • **role="combobox"** Combo boxes (input + dropdown)
  • **role="listbox"** Option lists
  • **role="option"** Individual options
  • **role="menu"** Menu widgets
  • **role="menubar"** Menu bars
  • **role="menuitem"** Menu items
  • **role="menuitemcheckbox"** Checkable menu items
  • **role="menuitemradio"** Radio menu items
  • **role="tab"** Tab controls
  • **role="tablist"** Tab containers
  • **role="tabpanel"** Tab content panels
  • **role="tree"** Tree views
  • **role="treeitem"** Tree items
  • **role="treegrid"** Editable tree grids
  • **role="grid"** Interactive grids
  • **role="gridcell"** Grid cells
  • **role="link"** Links
  • **role="progressbar"** Progress indicators
  • **role="scrollbar"** Scrollbars

Composite Roles

For grouping things together.

  • **role="group"** Generic groups
  • **role="radiogroup"** Radio button groups
  • **role="rowgroup"** Row groups in tables

Live Region Roles

For content that changes dynamically.

  • **role="alert"** Urgent messages
  • **role="log"** Logs that get appended to
  • **role="marquee"** Non-essential updates
  • **role="status"** Status messages
  • **role="timer"** Timers and countdowns

Window Roles

For modal interactions.

  • **role="dialog"** Dialog boxes
  • **role="alertdialog"** Alert dialogs

Abstract Roles (Never Use These)

These exist in the spec but aren’t meant for direct use: command, composite, input, landmark, range, roletype, section, sectionhead, select, structure, widget, window

Widget Attributes: Describing Interactions

These tell users how they can interact with elements.

  • **aria-autocomplete="none|inline|list|both"** Autocomplete behavior
  • **aria-checked="true|false|mixed"** Check state
  • **aria-disabled="true|false"** Disabled state
  • **aria-errormessage="[ID]"** Links to error messages
  • **aria-expanded="true|false|undefined"** Expansion state
  • **aria-haspopup="true|false|menu|listbox|tree|grid|dialog"** Indicates popup
  • **aria-hidden="true|false|undefined"** Visibility to assistive tech
  • **aria-invalid="true|false|grammar|spelling"** Validation state
  • **aria-label="[string]"** Accessible label
  • **aria-level="[integer]"** Hierarchical level
  • **aria-modal="true|false"** Modal state
  • **aria-multiline="true|false"** Multi-line input
  • **aria-multiselectable="true|false"** Multiple selection
  • **aria-orientation="horizontal|vertical|undefined"** Orientation
  • **aria-placeholder="[string]"** Placeholder hints
  • **aria-pressed="true|false|mixed|undefined"** Toggle state
  • **aria-readonly="true|false"** Read-only state
  • **aria-required="true|false"** Required fields
  • **aria-selected="true|false|undefined"** Selection state
  • **aria-sort="ascending|descending|none|other"** Sort direction
  • **aria-valuemax="[number]"** Maximum value
  • **aria-valuemin="[number]"** Minimum value
  • **aria-valuenow="[number]"** Current value
  • **aria-valuetext="[string]"** Human-readable value

Live Region Attributes: Handling Dynamic Content

These control how changes are announced to users.

  • **aria-atomic="true|false"** Announce whole region or just changes
  • **aria-busy="true|false"** Loading state
  • **aria-live="off|polite|assertive"** Announcement urgency
  • off No announcements
  • polite Announce when idle
  • assertive Interrupt to announce
  • **aria-relevant="additions|removals|text|all"** - What changes to announce

Drag and Drop Attributes

  • **aria-dropeffect="copy|move|link|execute|popup|none"** Drop effect (deprecated in ARIA 1.1)
  • **aria-grabbed="true|false|undefined"** Drag state (deprecated in ARIA 1.1)

Relationship Attributes: Connecting Elements

These create semantic relationships between elements.

  • **aria-activedescendant="[ID]"** Currently active child
  • **aria-colcount="[integer]"** Total columns
  • **aria-colindex="[integer]"** Column position
  • **aria-colspan="[integer]"** Columns spanned
  • **aria-controls="[ID list]"** Controlled elements
  • **aria-describedby="[ID list]"** Description sources
  • **aria-details="[ID]"** Detailed description
  • **aria-flowto="[ID list]"** Reading order override
  • **aria-labelledby="[ID list]"** Label sources
  • **aria-owns="[ID list]"** Owned children
  • **aria-posinset="[integer]"** Position in set
  • **aria-rowcount="[integer]"** Total rows
  • **aria-rowindex="[integer]"** Row position
  • **aria-rowspan="[integer]"** Rows spanned
  • **aria-setsize="[integer]"** Set size

Global Attributes: Works Everywhere

  • **aria-atomic** (covered above)
  • **aria-busy** (covered above)
  • **aria-controls** (covered above)
  • **aria-current="page|step|location|date|time|true|false"** Current item indicator
  • **aria-describedby** (covered above)
  • **aria-details** (covered above)
  • **aria-disabled** (covered above)
  • **aria-dropeffect** (deprecated)
  • **aria-errormessage** (covered above)
  • **aria-flowto** (covered above)
  • **aria-grabbed** (deprecated)
  • **aria-haspopup** (covered above)
  • **aria-hidden** (covered above)
  • **aria-invalid** (covered above)
  • **aria-keyshortcuts="[string]"** - Keyboard shortcuts
  • **aria-label** (covered above)
  • **aria-labelledby** (covered above)
  • **aria-live** (covered above)
  • **aria-owns** (covered above)
  • **aria-relevant** (covered above)
  • **aria-roledescription="[string]"** Custom role description

Practical Examples You’ll Use Daily

Here’s how this stuff works in real code.

Example 1: Custom Toggle Button

<div role="button" 
     tabindex="0" 
     aria-pressed="false"
     onclick="this.setAttribute('aria-pressed', this.getAttribute('aria-pressed') === 'false')">
  Dark Mode
</div>
Enter fullscreen mode Exit fullscreen mode

Never use div for button, if you already have button

Example 2: Accessible Modal Dialog

<div role="dialog" 
     aria-modal="true" 
     aria-labelledby="dialog-title"
     aria-describedby="dialog-desc">
  <h2 id="dialog-title">Delete Item?</h2>
  <p id="dialog-desc">This action cannot be undone.</p>
  <button>Delete</button>
  <button>Cancel</button>
</div>
Enter fullscreen mode Exit fullscreen mode

Example 3: Form Validation

<label for="email">Email Address</label>
<input type="email" 
       id="email" 
       aria-required="true"
       aria-invalid="true" 
       aria-describedby="email-error">
<span id="email-error" role="alert">
  Please enter a valid email address
</span>
Enter fullscreen mode Exit fullscreen mode

Example 4: Expandable Section

<button aria-expanded="false" aria-controls="content-panel">
  Show More Details
</button>
<div id="content-panel" hidden>
  Additional content here...
</div>
Enter fullscreen mode Exit fullscreen mode

Example 5: Live Search Results

<label for="search">Search Products</label>
<input id="search" 
       type="search" 
       aria-controls="results"
       aria-describedby="results-count">
<div id="results" 
     role="region" 
     aria-live="polite">
  <span id="results-count">12 products found</span>
  <!-- Results list here -->
</div>
Enter fullscreen mode Exit fullscreen mode

Mistakes That Break Accessibility

Never replace semantic HTML

<!-- Wrong -->
<div role="button" onclick="submit()">Submit</div>
Enter fullscreen mode Exit fullscreen mode
<!-- Right -->
<button onclick="submit()">Submit</button>
Enter fullscreen mode Exit fullscreen mode

Keep states synchronized

<!-- Wrong - state never updates -->
<button aria-expanded="false" onclick="toggle()">Menu</button>
Enter fullscreen mode Exit fullscreen mode
<!-- Right - state updates with interaction -->
<!-- Right - state updates with interaction -->
<button aria-expanded="false" 
        onclick="this.setAttribute('aria-expanded', this.getAttribute('aria-expanded') === 'false')">
  Menu
</button>
Enter fullscreen mode Exit fullscreen mode

Never hide interactive content

<!-- Wrong - button is hidden from assistive tech -->
<button aria-hidden="true">Important Action</button>
Enter fullscreen mode Exit fullscreen mode
<!-- Right - only hide decorative elements -->
<span aria-hidden="true">★</span><button>Rate 5 Stars</button>
Enter fullscreen mode Exit fullscreen mode

Never overcomplicate things

<!-- Wrong - unnecessary aria-label -->
<h1 aria-label="Welcome">Welcome</h1>
Enter fullscreen mode Exit fullscreen mode
<!-- Right - text content is already accessible -->
<h1>Welcome</h1>
Enter fullscreen mode Exit fullscreen mode

Avoid role conflicts

<!-- Wrong - confusing semantics -->
<button role="heading">Navigation Item</button>
Enter fullscreen mode Exit fullscreen mode
<!-- Right - use proper elements -->
<h2>Navigation</h2><button>Navigation Item</button>
Enter fullscreen mode Exit fullscreen mode

Testing Your Implementation

You can’t just add ARIA and hope it works. Here’s how to verify:

  1. **Browser DevTools: **Chrome and Firefox have accessibility inspectors built in
  2. **Screen Readers: **Test with NVDA (Windows), JAWS (Windows), VoiceOver (Mac/iOS), TalkBack (Android)
  3. **Automated Tools: **Run axe DevTools, WAVE, or Lighthouse audits
  4. **Keyboard Navigation: **Try using your site with only Tab, Enter, Space, and Arrow keys
  5. **Real Users: **The gold standard is testing with actual assistive technology users

Quick Reference for Common Scenarios

Labeling elements:

  • aria-label Direct label text
  • aria-labelledby Reference another element's text
  • aria-describedby Additional description

Interactive states:

  • aria-expanded For expandable sections
  • aria-pressed For toggle buttons
  • aria-checked For custom checkboxes
  • aria-selected For selected options

Error handling:

  • aria-invalid Mark invalid fields
  • aria-errormessage Link to error text
  • role="alert" Announce errors immediately

Dynamic content:

  • aria-live="polite" Announce when convenient
  • aria-live="assertive" Announce immediately
  • aria-busy="true" While loading

Navigation:

  • aria-current="page" Current page in nav
  • aria-hidden="true" Hide decorative content
  • aria-controls Link trigger to content

Final Thoughts

ARIA can seem overwhelming when you see this huge list. But here’s you should know, you don’t need to memorize every attribute. Start with the common ones aria-label, aria-expanded, aria-hidden, aria-live. Learn the others as your projects need them.

What really matters is understanding why behind ARIA. It exists to make the web usable for everyone, regardless of how they access it. Every time you add proper ARIA attributes, you’re opening your website to more people. And that’s what the web is supposed to be about.

So start small, pick one component in your current project. Add the right ARIA attributes. Test it with a screen reader. You’ll be surprised how quickly it becomes second nature.

The web is better when everyone can use it. Now you have the tools to make that happen.

Did you learn something good today?
Then show some love. 🫰
©Usman Writes
WordPress Developer | Website Strategist | SEO Specialist
Don’t forget to subscribe to Developer’s Journey to show your support.

Top comments (2)

Collapse
 
cyrille37 profile image
Cyrille37

Thanks a lot for this great ARIA landscape :-)

Collapse
 
web_dev-usman profile image
Muhammad Usman

Glad you liked it.