ARIA Accessibility: A Developer’s Guide to Website Accessibility

wave design element
Students of Learn Computer Academy learning about ARIA accessibility

Your website could be blocking millions of users right now due to ARIA accessibility. Here’s how to fix it.

Did you know that over 1 billion people worldwide live with disabilities?

Yet, most websites remain inaccessible to them.

This isn’t just a moral issue. It’s a business problem.

Inaccessible websites lose customers. They face lawsuits. They miss opportunities.

But here’s the thing: making your website accessible doesn’t have to be complicated.

ARIA accessibility is your secret weapon.

My Wake-Up Call with ARIA Accessibility

Three years ago, I watched my friend Sarah struggle to buy concert tickets online.

She’s blind. Uses a screen reader.

The “Buy Now” button? Just said “Click here.”

The seat selection? A meaningless grid of divs.

She gave up after 20 minutes.

That’s when it hit me: We’re not just excluding users. We’re excluding customers, friends, family members.

Image showing person using screen reader
Image showing person using screen reader

The Numbers Don’t Lie

What Is ARIA Accessibility? (And Why It Matters More Than You Think)

ARIA stands for Accessible Rich Internet Applications.

Think of ARIA accessibility as a translator. It takes your complex web components and explains them to assistive technologies like screen readers.

Without ARIA accessibility, your dropdown menu is just a bunch of divs. Your image carousel? A meaningless pile of code.

With proper ARIA accessibility implementation, these become navigable, understandable interfaces.

The brutal truth? Most websites fail basic accessibility tests. Don’t let yours be one of them.

The Real Cost of Ignoring ARIA Accessibility

Here’s what happens when you skip ARIA accessibility:

Legal risks. Companies like Target, Netflix, and Domino’s have faced lawsuits. Millions in settlements.

Lost revenue. The disability market represents $13 trillion in annual disposable income globally.

SEO penalties. Google considers accessibility a ranking factor. Poor accessibility = poor rankings.

Brand damage. Social media doesn’t forgive accessibility failures.

Real Companies, Real Consequences

Target Corporation: $6 million settlement in 2006. Still fighting accessibility lawsuits today.

Domino’s Pizza: Supreme Court case. Spent more on legal fees than fixing their website would have cost.

Netflix: $755,000 settlement for inadequate closed captions.

BeyoncΓ©’s Website: Sued for accessibility violations. Even celebrities aren’t immune.

Screenshots of news headlines about accessibility lawsuits
Screenshots of news headlines about accessibility lawsuits

ARIA Accessibility Fundamentals Every Developer Must Know

The Three Pillars of ARIA Accessibility

1. Roles Tell assistive technologies what an element is.

2. Properties Describe the element’s current state.

3. States Explain what’s happening to the element.

Master these three concepts, and you’ll understand 90% of ARIA accessibility implementation.

How I Test ARIA in 5 Minutes

Here’s my quick accessibility audit process:

  • Step 1: Turn off your monitor. Navigate with Tab key only.
  • Step 2: Use a screen reader (NVDA is free for Windows).
  • Step 3: Check color contrast with WebAIM’s tool.
  • Step 4: Validate with axe DevTools.
  • Step 5: Test on mobile with voice control.

Can’t complete these steps? Your site fails accessibility.

Video screenshot showing screen reader navigation

ARIA Roles Cheat Sheet

1. Landmark Roles (Page Structure)

RoleWhat It DoesWhen To UseExample
bannerSite-wide headerOnce per page, top header
<header role="banner">...</header>
navigationNavigation menusFor main or secondary navigation
<nav role="navigation" aria-label="Main menu">...</nav>
mainMain content areaOnce per page
<main role="main">...</main>
complementaryRelated content sidebarSidebars, secondary content
<aside role="complementary">...</aside>
contentinfoSite-wide footer

Footer section

<footer role="contentinfo">...</footer>
searchSearch regionDedicated search forms
<form role="search">...</form>
regionGeneric landmark region

Any important section with label

<div role="region" aria-label="User settings">...</div>

formGrouping form controls

Forms
<form role="form">...</form>

2. Widget Roles (User Interface Controls)

RoleWhat It DoesWhen To UseExample
buttonClickable buttonButtons or links acting as buttons

<button role="button">Click me</button>
checkboxCheckable box

Checkboxes
<input type="checkbox" role="checkbox">
radioRadio button

Radio buttons

<input type="radio" role="radio">
radiogroupGroup of radio buttons

Group
<div role="radiogroup">...</div>
comboboxDropdown with search/filter

Dropdowns
<div role="combobox" aria-expanded="false">...</div>
listboxList of selectable options

Select lists

<div role="listbox">...</div>
optionOption in a listbox

Items in listbox

<div role="option" aria-selected="false">Option</div>
sliderAdjustable slider

Sliders
<div role="slider" aria-valuenow="50" aria-valuemin="0" aria-valuemax="100"></div>
spinbuttonNumeric input with increment/decrement

Numeric inputs

<input role="spinbutton" aria-valuenow="1" aria-valuemin="0" aria-valuemax="10">
textboxText input

Text fields

<input role="textbox" type="text">
searchboxSearch input

Search fields

<input role="searchbox" type="search">
menuMenu container

Menus
<ul role="menu">...</ul>
menubarMenu bar

Menu bars

<nav role="menubar">...</nav>
menuitemItem in a menu

Menu items

<li role="menuitem">Save</li>
menuitemcheckboxCheckable menu item

Checkable menu items

<li role="menuitemcheckbox" aria-checked="false">...</li>
menuitemradio

Radio menu item

Radio menu items

<li role="menuitemradio" aria-checked="true">...</li>
tabTab in tablist

Tabs
<button role="tab" aria-selected="true">Tab 1</button>
tablistContainer for tabs

Tabs container

<div role="tablist">...</div>
tabpanelTab panel

Panels controlled by tabs

<div role="tabpanel">...</div>
tooltipTooltip information

Tooltips
<div role="tooltip">More info</div>
scrollbarScrollbar control

Custom scrollbars<div role="scrollbar" aria-valuenow="10" aria-valuemin="0" aria-valuemax="100"></div>

3. Document Structure Roles

RoleWhat It DoesWhen To UseExample
articleSelf-contained content

Articles, blog posts, comments

<article role="article">...</article>
sectionThematic grouping of content

Sections within pages
<section role="region" aria-label="News">...</section>
headingSection heading

Headings with levels

<h2 role="heading" aria-level="2">Title</h2>
listList of items

Lists
<ul role="list">...</ul>
listitemItem in a list

List items

<li role="listitem">...</li>
rowRow in a grid or table

Table rows

<tr role="row">...</tr>
rowgroupGroup of rows

Table body or header groups

<tbody role="rowgroup">...</tbody>
columnheaderColumn header

Table column headers

<th role="columnheader">Name</th>
rowheaderRow header

Table row headers

<th role="rowheader">...</th>
tableTable container

Tables
<table role="table">...</table>
gridGrid or spreadsheet

Complex tabular data

<table role="grid">...</table>
gridcellCell in grid

Grid cells

<td role="gridcell">...</td>
treeTree widget

Trees
<ul role="tree">...</ul>
treeitemItem in tree

Tree nodes

<li role="treeitem">...</li>
treegridTree with grid structure

Complex trees

<table role="treegrid">...</table>
aria-level

Work like h1, h2 etc tag

If you not use like h1,h2 etc tags then you can declear using aria-level, browser will understand its heading tag. aria-level-1 to aria-level-6 same as h1 to h6

<div aria-level="1"><div>

4. Live Regions and Status

RoleWhat It Does
When To Use
Example
alertImportant, usually time-sensitive info

For error messages and alerts

<div role="alert">Error loading data</div>
alertdialogModal alert requiring interaction

Critical dialogs needing immediate attention

<div role="alertdialog" aria-modal="true">...</div>
logLive region with log updates

For live logs

<div role="log" aria-live="polite">...</div>
marqueeScrolling text live region

Scrolling news or info

<div role="marquee">Breaking news</div>
statusStatus messages

Informational live updates

<div role="status" aria-live="polite">Saved!</div>
timerTime-related live region

Countdown timers

<div role="timer" aria-live="assertive">1:00</div>

5. Miscellaneous Roles

RoleWhat It Does
When To Use
Example
applicationComplex web application

Rare, for apps with custom keyboard interactions

<div role="application">...</div>
groupGrouping related elements

Group form fields or controls

<div role="group">...</div>
noteAdvisory or supplementary info

Side notes or tips

<aside role="note">...</aside>
presentationLayout or decoration only

Elements ignored by assistive tech

<div role="presentation">...</div>
separatorDivider between sections

Dividers in menus/toolbars

<div role="separator"></div>

ARIA Attributes Cheat Sheet

1. Naming and Labeling Attributes

AttributePurposeExample
aria-label

Provides an accessible name (text label)

<button aria-label="Close menu"></button>
aria-labelledby

References one or more elements that label this

<div aria-labelledby="header1">...</div>
aria-describedby

References element(s) that describe this element

<input aria-describedby="hint1">
aria-valuetext

Overrides the text representation of a value

<div role="slider" aria-valuetext="Halfway"></div>

2. State and Property Attributes

AttributePurposeValues / Usage Examples
aria-hidden

Hides element from assistive tech

“true” or “false”

aria-disabled

Indicates element is disabled

“true” or “false”

aria-checked

Check state for checkbox, radio, or menuitemcheckbox

“true”, “false”, or “mixed”

aria-selected

Indicates selection in list, grid, tablist, etc.

“true” or “false”

aria-expanded

Shows if expandable element is expanded

“true” or “false”

aria-pressed

Toggle button pressed state

“true”, “false”, or “mixed”

aria-required

Marks input as required

“true” or “false”

aria-readonly

Element is read-only

“true” or “false”

aria-busy

Indicates loading or updating content

“true” or “false”

3. Relationships and Ownership Attributes

AttributePurposeExample
aria-controls

Identifies element(s) controlled by this element

<button aria-controls="menu1">Toggle Menu</button>
aria-owns

Creates a parent/child relationship not in DOM

<div aria-owns="item1 item2">...</div>
aria-activedescendant

Identifies currently active child element

<input aria-activedescendant="option3">
aria-flowto

Indicates next element in reading order

<div aria-flowto="section2">...</div>

4. Live Region Attributes

AttributePurposeValues / Usage Examples
aria-live

Announces dynamic updates to assistive tech

“off”, “polite”, “assertive”

aria-atomic

Whether updates are presented as a whole or partial

“true” or “false”

aria-relevant

What types of changes are relevant for announcements

“additions”, “removals”, “text”

5. Widget-Specific Attributes

AttributePurposeExample / Values
aria-valuenow

Current value for slider, spinbutton, progressbar

<div role="slider" aria-valuenow="50">
aria-valuemin

Minimum value

<div role="slider" aria-valuemin="0">
aria-valuemax

Maximum value

<div role="slider" aria-valuemax="100">
aria-colcount

Number of columns in a grid or table

<table aria-colcount="5">
aria-rowcount

Number of rows in a grid or table

<table aria-rowcount="10">
aria-colindex

Index of column

<td aria-colindex="3">
aria-rowindex

Index of row

<tr aria-rowindex="2">

6. Modal and Dialog Attributes

AttributePurposeExample
aria-modal

Indicates a modal dialog

<div role="dialog" aria-modal="true">...</div>
aria-describedby

Description for dialog or alert

<div id="desc1">Form is required</div><div role="alert" aria-describedby="desc1">Error</div>

7. Miscellaneous Attributes

AttributePurposeExample
aria-live

Live region announcements

<div aria-live="polite">Content updated</div>
aria-atomic

Atomic updates of live region

“true” or “false”

aria-haspopup

Indicates presence of popup/menu/dialog

<button aria-haspopup="true">Open Menu</button>
aria-level

Heading or treeitem level

<h2 role="heading" aria-level="2">Section title</h2>

Tabindex Accessibility Cheat Sheet

This cheat sheet helps you apply tabindex properly for keyboard accessibility, aligning with best practices for semantic HTML, ARIA, and accessible design.

πŸ”’ Tabindex Values & Their Meaning

tabindex Value

Descriptionβœ… Use When

❌ Avoid When

tabindex=”0″

Includes an element in the natural tab order

For custom elements like
<div role="button">
or accessible widgets

On elements already natively focusable like
<a>, <button>


tabindex=”-1″

Focusable only via JavaScript, not by tabbing
For programmatic focus (e.g., modals, alerts, skip links)

If keyboard users need to reach it with Tab

tabindex=”1+”

Overrides natural order with custom tab flow (discouraged)

Very specific UI needs (e.g., legacy systems or game-like interfaces)

Most cases β€” it disrupts expected navigation

❌ Elements That Don’t Need tabindex="0"

ElementReason
<a href="...">Already keyboard-focusable

<button>Already in tab order

<input>Naturally focusable

<select>Naturally focusable

<textarea>Naturally focusable

<summary>Focusable by default in


βœ… Elements That MAY Need tabindex="0" (When Interactive)

ElementRecommended Usage
<div>If used as button, link, tab, etc. with appropriate ARIA role

<span>Same as
<div>
, when made interactive

<li>When part of custom components like tabs or menus

<img>Only when interactive (e.g., image gallery navigation)

<svg>For clickable icons or custom controls

<section>When used as a focusable landmark for keyboard navigation

<article>Same as above β€” use tabindex=”0″ only for meaningful keyboard stops

πŸ’‘ Best Practices

  • Never use positive tabindex (tabindex="1" or more) unless absolutely required.
  • Use tabindex="-1" to trap focus temporarily (e.g., in modals).
  • Combine tabindex="0" with proper roles (role="button", role="link") and keyboard support (Enter, Space handlers).
  • Avoid cluttering the page with unnecessary focus targets β€” focus should only land on meaningful elements.

The 7 Deadly ARIA Sins (I’ve Made Them All)

  • Sin #1: Using role="button" without keyboard support Fix: Add tabindex="0" and Enter/Space handlers
  • Sin #2: aria-label on non-interactive elements Fix: Use aria-labelledby or regular text instead
  • Sin #3: Redundant ARIA roles Bad: <button role="button"> Good: <button> (it’s already a button!)
  • Sin #4: Hiding important content with aria-hidden="true" Fix: Only hide decorative elements
  • Sin #5: Forgetting to update dynamic content Fix: Use aria-live regions for status updates
  • Sin #6: Positive tabindex values Bad: tabindex="1" Good: Let natural tab order work
  • Sin #7: No focus indicators Fix: Add visible focus styles for keyboard users
Before-after code examples screenshot of bad and good accessible code
Before-after code examples screenshot of bad and good accessible code

My Accessibility Testing Toolkit

Free Tools:

Screen Readers:

Manual Testing:

  • Keyboard-only navigation
  • High contrast mode
  • Zoom to 200%
  • Mobile voice control

Your ARIA Implementation Roadmap

Week 1: Audit current site

  • Run axe DevTools on top 10 pages
  • Document all issues
  • Prioritize by impact

2nd Week: Fix the basics

  • Add alt text to images
  • Ensure proper heading structure
  • Test keyboard navigation

Week 3: Implement ARIA

  • Add roles to custom components
  • Set up live regions
  • Test with screen readers

Week 4: Advanced features

  • Complex widgets (carousels, dropdowns)
  • Dynamic content handling
  • Mobile accessibility
ARIA implementation Roadmap
ARIA implementation Roadmap

Does ARIA Slow Down Your Site?

Short answer: No.

ARIA attributes add minimal bytes to your HTML.

The real performance killer? Inaccessible sites that exclude users.

Accessibility = Better UX for Everyone

  • Clear navigation helps all users
  • Good contrast improves readability
  • Semantic HTML boosts SEO
  • Keyboard support helps power users

Ready to Build a Web That Works for Everyone?

The choice is yours.

You can keep excluding 1 billion people.

Or you can start today.

Fix one component.

Add one ARIA label.

Test with one screen reader.

Every accessible feature is a person who can now buy from you.

ARIA isn’t about compliance.

It’s about customers.

Your users are waiting.

What are you waiting for?

Subscribe
Notify of
0 Comments
Inline Feedbacks
View all comments