HTML course menu
ARIA Basics: Roles, aria-label, aria-expanded and the First Rule of ARIA
Learn what ARIA is and when to use it: the first rule of ARIA, roles, accessible names with aria-label and aria-labelledby, descriptions with aria-describedby, states such as aria-expanded and aria-current, aria-hidden, and live regions.
On this page
ARIA (Accessible Rich Internet Applications) is a set of attributes that add accessibility information to HTML: what an element is (its role), what it is called (its name), and what state it is in (expanded, selected, current). Screen readers and other assistive technology use this information.
ARIA only changes what assistive technology is told. It does not add any behaviour: an element given role="button" still does not respond to the keyboard unless you write JavaScript for it.
The first rule of ARIA#
The W3C's guidance on using ARIA starts with this rule, in short: if a native HTML element already has the meaning and behaviour you need, use it instead of adding ARIA.
<!-- Avoid -->
<div role="button" tabindex="0">Save</div>
<!-- Prefer -->
<button type="button">Save</button>The <button> is focusable, works with Enter and Space, and is announced as a button, all for free. Badly used ARIA can make a page worse than no ARIA at all, because it can announce things that are not true.
Accessible names#
Every interactive element needs a name that assistive technology can announce. Normally it comes from the content or a <label>. When there is no visible text, use ARIA:
aria-label#
<button type="button" aria-label="Close">✕</button>
<nav aria-label="Breadcrumb">...</nav>A screen reader announces "Close, button" instead of a meaningless symbol. Two <nav> elements can be told apart by their labels.
aria-labelledby#
Points to the id of visible text that already names the element:
<section aria-labelledby="pricing-heading">
<h2 id="pricing-heading">Pricing</h2>
...
</section>Prefer visible text with aria-labelledby over aria-label: sighted users see the same name, and translation tools translate it.
aria-describedby#
Adds a description that is read after the name, such as a hint or an error:
<label for="pwd">Password</label>
<input type="password" id="pwd" aria-describedby="pwd-rules">
<p id="pwd-rules">At least 12 characters.</p>States#
ARIA states tell users about things that change. Your JavaScript must update them when the state changes.
<button type="button" aria-expanded="false" aria-controls="menu">Menu</button>
<ul id="menu" hidden>
<li><a href="/" aria-current="page">Home</a></li>
<li><a href="/courses">Courses</a></li>
</ul>When JavaScript opens the menu, it removes hidden and sets aria-expanded="true".
Hiding decorative content: aria-hidden#
aria-hidden="true" removes an element from what assistive technology sees, while it stays visible on screen. Use it for decorative icons next to text:
<button type="button"><span aria-hidden="true">🗑️</span> Delete</button>Never put aria-hidden="true" on something focusable, such as a link or button: keyboard users could then focus something a screen reader does not announce.
Live regions#
When content changes without a page reload (a "Saved!" message, a cart count, a search result count), screen reader users do not notice unless you tell them. A live region announces its changes:
<p role="status">3 results found</p>
<p role="alert">Your session will expire in 1 minute.</p>role="status"(same asaria-live="polite") waits for a pause before announcing.role="alert"(same asaria-live="assertive") interrupts immediately; keep it for urgent messages.
The region should already be on the page before its text changes.
Common roles you will meet#
The W3C's ARIA Authoring Practices Guide shows complete, tested patterns for widgets that have no native element, such as tabs, comboboxes and menus.
Practice#
Practice exercise
Improve this markup with the right ARIA (and fix anything that does not need ARIA):
<div role="button" onclick="toggleFaq()">Show answers</div>
<div id="answers" style="display:none">...</div>
<a href="/search"><img src="search-icon.svg"></a>Show solution
<button type="button" aria-expanded="false" aria-controls="answers" onclick="toggleFaq()">Show answers</button>
<div id="answers" hidden>...</div>
<a href="/search"><img src="search-icon.svg" alt="Search"></a>- A native
<button>replaces the ARIA button and gets keyboard support for free. aria-expandedandaria-controlsdescribe the toggle; the JavaScript must switcharia-expandedto"true"when it shows the answers.- The icon link needed a name. The image's alt text provides it, so no ARIA is needed.
Key takeaway#
Finished this lesson?