aria-busy Loading Indicator

Set 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.

1. Block Elements — <article aria-busy="true">

Any block element with aria-busy="true" hides its content and shows a centered spinner. Click to toggle.

Card Title

This content is hidden while aria-busy="true" is set. Click the card to toggle.

Loaded Card

This card has loaded. Click to set it to loading state.

Another Card

Also loading. Click to reveal content.

2. Inline Elements — <span aria-busy="true">

Inline elements show a small spinner before the text. Useful for inline loading status messages.

  • Profile picture Uploading…
  • Email verification Sending…
  • Payment Complete

3. Buttons — <button aria-busy="true">

Buttons show a spinner that replaces the text. Click any button to toggle aria-busy.

4. Table — <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 Email Status
Alice Johnson alice@example.com Active
Bob Smith bob@example.com Pending

5. Full Section — <section aria-busy="true">

Any container element works. Click the section below to toggle loading.

Dashboard Summary

Revenue: $12,450 — Users: 1,234 — Orders: 89

Implementation: 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>