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 -
offNo announcements -
politeAnnounce when idle -
assertiveInterrupt 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>
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>
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>
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>
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>
Mistakes That Break Accessibility
Never replace semantic HTML
<!-- Wrong -->
<div role="button" onclick="submit()">Submit</div>
<!-- Right -->
<button onclick="submit()">Submit</button>
Keep states synchronized
<!-- Wrong - state never updates -->
<button aria-expanded="false" onclick="toggle()">Menu</button>
<!-- 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>
Never hide interactive content
<!-- Wrong - button is hidden from assistive tech -->
<button aria-hidden="true">Important Action</button>
<!-- Right - only hide decorative elements -->
<span aria-hidden="true">★</span><button>Rate 5 Stars</button>
Never overcomplicate things
<!-- Wrong - unnecessary aria-label -->
<h1 aria-label="Welcome">Welcome</h1>
<!-- Right - text content is already accessible -->
<h1>Welcome</h1>
Avoid role conflicts
<!-- Wrong - confusing semantics -->
<button role="heading">Navigation Item</button>
<!-- Right - use proper elements -->
<h2>Navigation</h2><button>Navigation Item</button>
Testing Your Implementation
You can’t just add ARIA and hope it works. Here’s how to verify:
- **Browser DevTools: **Chrome and Firefox have accessibility inspectors built in
- **Screen Readers: **Test with NVDA (Windows), JAWS (Windows), VoiceOver (Mac/iOS), TalkBack (Android)
- **Automated Tools: **Run axe DevTools, WAVE, or Lighthouse audits
- **Keyboard Navigation: **Try using your site with only Tab, Enter, Space, and Arrow keys
- **Real Users: **The gold standard is testing with actual assistive technology users
Quick Reference for Common Scenarios
Labeling elements:
-
aria-labelDirect label text -
aria-labelledbyReference another element's text -
aria-describedbyAdditional description
Interactive states:
-
aria-expandedFor expandable sections -
aria-pressedFor toggle buttons -
aria-checkedFor custom checkboxes -
aria-selectedFor selected options
Error handling:
-
aria-invalidMark invalid fields -
aria-errormessageLink 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-controlsLink 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)
Thanks a lot for this great ARIA landscape :-)
Glad you liked it.