-
Section 1: Getting Started
-
Section 2: Core Syntax and Types
-
Section 3: Strings and Numbers in Depth
-
Section 4: Control Flow
-
Section 5: Functions
-
Section 6: Objects and Arrays
-
Section 7: Maps, Sets, and Symbols
-
Section 8: Asynchronous JavaScript
-
Section 9: Object-Oriented and Prototypes
-
Section 10: The DOM
-
Section 11: Browser APIs
-
Section 12: Modern JavaScript (ES2015-ES2025)
-
Section 13: Functional Programming Patterns
-
Section 14: Error Handling and Debugging
-
Section 15: Testing
-
Section 16: Accessibility for JavaScript Developers
-
Section 17: Internationalization and Localization
-
Section 18: Performance
-
Section 19: Node.js Fundamentals
-
Section 20: Regular Expressions
-
Section 21: Design Patterns in JavaScript
-
Section 22: Security Basics
-
Section 23: Data Structures and Algorithms in JavaScript
-
Section 24: Practical Projects
-
Section 25: More Advanced Async Patterns
-
Section 26: More Object and Class Practice
-
Section 27: Working with Dates and Internationalization
-
Section 28: Web Components
-
Section 29: More DOM and Browser Practice
-
Section 30: Build Tooling for Vanilla JavaScript
-
Section 31: More Practice Projects
-
Section 32: Interview and Algorithm Practice
-
Section 33: Error Objects (MDN Reference)
-
Section 34: TypedArrays and Binary Data
-
Section 35: Reflection and Metaprogramming (MDN Reference)
-
Section 36: More Global Functions (MDN Reference)
129: ARIA Roles and Live Regions in Dynamic UIs
Most of the time, when we update the DOM with JavaScript, we're thinking about the visual transition. We see the list filter, the spinner disappear, or the error message pop up. But for someone using a screen reader, the page is essentially static unless the focus moves. If you update a piece of text in a div, the screen reader doesn't magically announce it—the user has no idea anything happened.
To fix this, we use ARIA (Accessible Rich Internet Applications) roles and live regions. Let's build a real-time search filter for a user directory to see this in action.
Setting up the search list
I'll start with a basic input and a list of names. Nothing fancy here; just standard HTML. I want a place where I can explicitly tell the user how many results were found, because that's the piece of information that changes dynamically.
<div class="search-container">
<input type="text" id="user-search" placeholder="Search users...">
<p id="results-count">Showing all users</p>
<ul id="user-list">
<li>Alice</li>
<li>Bob</li>
<li>Charlie</li>
<li>Diana</li>
</ul>
</div>
Making the filter actually work
Now for the JavaScript. I'm going to listen for the input event and toggle the visibility of the list items. I'll also update the text of that results count paragraph so the visual user knows what's happening.
const searchInput = document.getElementById('user-search');
const resultsCount = document.getElementById('results-count');
const users = document.querySelectorAll('#user-list li');
searchInput.addEventListener('input', (e) => {
const term = e.target.value.toLowerCase();
let count = 0;
users.forEach(user => {
const match = user.textContent.toLowerCase().includes(term);
user.style.display = match ? '' : 'none';
if (match) count++;
});
resultsCount.textContent = `Found ${count} user${count === 1 ? '' : 's'}`;
});
The invisible wall: Why users can't "hear" the results
If you run this now and use a screen reader (like VoiceOver or NVDA), you'll notice a problem: as you type, the list shrinks and the "Found X users" text updates, but the screen reader stays silent. It's still focused on the input box. The user has to manually tab away from the search box to find out if their search actually returned anything.
This is where aria-live comes in. By adding aria-live="polite" to our results count, we tell the browser: "When the text inside this element changes, please announce it to the user, but don't interrupt them if they're in the middle of doing something else."
I'm also going to add role="status". While aria-live="polite" does the heavy lifting, role="status" is a specialized ARIA role that implies a polite live region, making our intent clearer to different assistive technologies.
<p id="results-count" role="status" aria-live="polite">Showing all users</p>
Tuning the noise with polite live regions
Here is where I usually make a mistake when I'm in a rush: I'm tempted to use aria-live="assertive". I think, "I want the user to know immediately that the results changed!"
Don't do that. I tried it on a similar project last year, and it was a nightmare. assertive interrupts the screen reader mid-sentence. Since this is a search input, the screen reader is already announcing the letters as the user types. If I use assertive, the "Found 3 users" announcement will cut off the announcement of the character they just typed. It creates a stuttering, chaotic experience.
Stick with polite for search results. It waits for a natural pause in the speech flow before announcing the update. It's a much smoother experience for the user. If you were building a critical system error or a session timeout warning, assertive would be the right call—but for a search filter, it's overkill.
📋 Practical Task
Build a Live Validation Message for a Password Field
Create a password input field and a sibling div or span that acts as a validation message. Write a JavaScript function that checks the password length as the user types. If the password is shorter than 8 characters, display "Password too short" in the message element; otherwise, display "Password length is valid."
Your goal is to ensure that a screen reader user is notified of the validation status automatically without having to move their focus away from the input field. Apply the correct ARIA role and live region attributes to the message element to ensure the notification is helpful but not disruptive.
There are no comments for now.