Clean Markup

Announcing Dynamic UI Changes with ARIA Live Regions

Announcing Dynamic UI Changes with ARIA Live Regions

When a traditional multi-page website submits a form, the browser loads a new document and screen readers automatically start announcing the new page title and status message. In modern JavaScript interfaces, however, we often update a toast banner, search result count, or validation message dynamically in the DOM without reloading the page.

Without an ARIA Live Region (aria-live="polite" or role="status"), screen readers have no idea that text elsewhere on the page just changed.

Example

<!-- Present in the DOM on initial render so the screen reader tracks it -->
<div id="search-status" role="status" aria-live="polite" class="sr-status"></div>

Input : Dynamic JavaScript search filter or async form submission
Output : Screen-reader announcement of updated counts and status messages without stealing keyboard focus.

Implementation

<div class="filter-bar">
  <label for="topic-filter">Filter Articles</label>
  <input id="topic-filter" type="search" placeholder="e.g. CSS Grid" />

  <!-- Live region stays in the DOM and announces text mutations politely -->
  <p id="filter-status" role="status" aria-live="polite" aria-atomic="true">
    Showing all 18 articles.
  </p>
</div>
var filterInput = document.getElementById("topic-filter");
var statusRegion = document.getElementById("filter-status");

function updateFilterStatus(matchingCount, query) {
  if (!statusRegion) return;

  if (!query) {
    statusRegion.textContent = "Showing all articles.";
    return;
  }

  statusRegion.textContent =
    matchingCount +
    (matchingCount === 1 ? " article" : " articles") +
    ' found for "' +
    query +
    '".';
}

if (filterInput) {
  filterInput.addEventListener("input", function (event) {
    var query = event.target.value.trim();
    // Example count after filtering DOM cards
    var visibleCards = document.querySelectorAll(".postlist-item:not([hidden])");
    updateFilterStatus(visibleCards.length, query);
  });
}

Main Point: Always render the aria-live="polite" container in the initial HTML markup and mutate its textContent when updates occur; injecting a brand-new aria-live element dynamically at the same moment as its text is often ignored by assistive technologies.

Credits

Photo by John Schnobrich

← Home