Card Title
This content is hidden while aria-busy="true" is set. Click the card to toggle.
aria-busy Loading IndicatorSet aria-busy="true" on any HTML element to show a loading spinner. One CSS rule — no custom classes, no JS. The same native attribute that screen readers already understand.
aria-busy attribute is a native ARIA attribute supported by all browsers.
CSS targets [aria-busy="true"] to show a spinner via ::before or ::after pseudo-elements.
When loading completes, remove the attribute — the spinner disappears and screen readers announce the content is ready.
No JavaScript needed — pure CSS.
<article aria-busy="true">Any block element with aria-busy="true" hides its content and shows a centered spinner. Click to toggle.
This content is hidden while aria-busy="true" is set. Click the card to toggle.
This card has loaded. Click to set it to loading state.
Also loading. Click to reveal content.
<span aria-busy="true">Inline elements show a small spinner before the text. Useful for inline loading status messages.
<button aria-busy="true">Buttons show a spinner that replaces the text. Click any button to toggle aria-busy.
<tbody aria-busy="true">Set aria-busy on a <tbody> to show a loading state for table data. Click the table body to toggle.
| Name | Status | |
|---|---|---|
| Alice Johnson | alice@example.com | Active |
| Bob Smith | bob@example.com | Pending |
<section aria-busy="true">Any container element works. Click the section below to toggle loading.
Revenue: $12,450 — Users: 1,234 — Orders: 89
aria-busy loading (complete CSS)<style>
@keyframes spin {
to { transform: rotate(360deg); }
}
/* Block elements: centered spinner, hide children */
[aria-busy="true"]:not(button) {
display: flex;
align-items: center;
justify-content: center;
min-height: 3rem;
}
[aria-busy="true"]:not(button)::before {
content: '';
width: 1.5rem;
height: 1.5rem;
border: 3px solid #dee2e6;
border-top-color: var(--bs-primary);
border-radius: 50%;
animation: spin 0.6s linear infinite;
}
[aria-busy="true"]:not(button) > * {
display: none;
}
/* Buttons: spinner replaces text */
button[aria-busy="true"] {
position: relative;
pointer-events: none;
color: transparent !important;
}
button[aria-busy="true"]::after {
content: '';
position: absolute;
top: 50%; left: 50%;
width: 1.25rem; height: 1.25rem;
margin: -0.625rem 0 0 -0.625rem;
border: 3px solid rgba(255,255,255,0.3);
border-top-color: #fff;
border-radius: 50%;
animation: spin 0.6s linear infinite;
}
</style>
<!-- Block element loading -->
<article aria-busy="true">
Content hidden while loading...
</article>
<!-- Inline loading -->
<span aria-busy="true">Uploading...</span>
<!-- Button loading -->
<button aria-busy="true" aria-label="Loading">
Submit
</button>
<!-- Toggle loading via JS -->
<script>
// Start loading
element.setAttribute('aria-busy', 'true');
// Done loading
element.removeAttribute('aria-busy');
</script>