aria-busy
Indicates an element is being modified and that assistive technologies may want to wait until the modifications are complete before exposing the changes to the user.
Overview
The aria-busy attribute tells assistive technologies that an element is currently being updated. When set to true, screen readers should wait before announcing changes.
This is particularly useful when making multiple rapid changes to a live region. Set it to true before starting updates, then back to false when complete. The screen reader will then announce the final result once.
Why Use aria-busy?
Without aria-busy, screen readers might announce each intermediate change during a complex update. This creates a flood of announcements. Setting aria-busy="true" tells them to wait for the final result.
Live Demo: aria-busy Behavior
Initial content
Current aria-busy state: false
Screen readers will announce the content
Attribute Values
trueThe element and its subtree are currently being updated. Assistive technologies should wait before announcing changes. Use this during async operations, batch updates, or DOM manipulations.
false(default)The element is not currently being updated. This is the normal state. Assistive technologies will announce changes as they occur. This is the default when the attribute is omitted.
Code Examples
Basic Pattern
<!-- Basic aria-busy Usage -->
<div id="content-area"
role="region"
aria-live="polite"
aria-busy="false">
<p>Content will appear here</p>
</div>
<script>
function loadContent() {
const container = document.getElementById('content-area');
// Set busy to true before loading
container.setAttribute('aria-busy', 'true');
// Fetch data
fetch('/api/data')
.then(response => response.json())
.then(data => {
// Update content
container.innerHTML = data.html;
// Set busy to false when complete
container.setAttribute('aria-busy', 'false');
// Screen reader will now announce the new content
});
}
</script>Batch Updates
<!-- Multiple Sequential Updates -->
<div id="feed"
role="feed"
aria-live="polite"
aria-busy="false">
<article>Post 1</article>
<article>Post 2</article>
</div>
<script>
async function loadMorePosts() {
const feed = document.getElementById('feed');
// Start batch update
feed.setAttribute('aria-busy', 'true');
// Load multiple posts
const posts = await fetchPosts();
// Add all posts
posts.forEach(post => {
const article = document.createElement('article');
article.textContent = post.title;
feed.appendChild(article);
});
// Finish batch update
feed.setAttribute('aria-busy', 'false');
// Screen reader announces: "5 new articles added"
// (instead of announcing each one individually)
}
</script>React Examples
// React Component with aria-busy
import { useState } from 'react';
function DataTable({ dataUrl }) {
const [data, setData] = useState([]);
const [isLoading, setIsLoading] = useState(false);
const loadData = async () => {
setIsLoading(true);
try {
const response = await fetch(dataUrl);
const newData = await response.json();
setData(newData);
} catch (error) {
console.error('Failed to load:', error);
} finally {
setIsLoading(false);
}
};
return (
<div
role="region"
aria-live="polite"
aria-busy={isLoading}
aria-label="Data Table"
>
{isLoading ? (
<div className="loading">
<span className="spinner" aria-hidden="true"></span>
<span>Loading data...</span>
</div>
) : (
<table>
<thead>
<tr>
<th>Name</th>
<th>Value</th>
</tr>
</thead>
<tbody>
{data.map(item => (
<tr key={item.id}>
<td>{item.name}</td>
<td>{item.value}</td>
</tr>
))}
</tbody>
</table>
)}
<button onClick={loadData} disabled={isLoading}>
{isLoading ? 'Loading...' : 'Refresh Data'}
</button>
</div>
);
}Best Practices
Set aria-busy="true" BEFORE making changes to the live region
Set aria-busy="false" AFTER all changes are complete
Use for batch updates or multiple sequential DOM changes
Combine with aria-live to create effective loading states
Always reset to false - forgetting breaks future announcements
Use for async data loading that replaces region content
Don't leave aria-busy="true" indefinitely
Don't use for single, simple updates that don't need batching
Don't forget to set it back to false - critical!
Don't use as a general "loading" indicator without live regions
Accessibility Notes
Prevents Announcement Spam
When making rapid or multiple changes to a live region, aria-busy="true" prevents screen readers from interrupting the user with each individual change. Set it to false when done, and the final state will be announced once.
Critical: Always Reset
Always remember to set aria-busy back to false! Forgetting to do this will prevent all future announcements from the live region. Use try/finally blocks or cleanup functions to ensure it's reset even if errors occur.
Browser Behavior
Different screen readers may handle aria-busy slightly differently. Some may queue announcements, while others may discard them entirely until busy is false. Test across platforms to ensure consistent behavior.