October DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsWindows FixRecommendedWindows errors stealing your time? Find the fix fastScan stability, cleanup and performance issues.Fix NowOctober DealsAmazon USDeal season is back - check today's better picksAmazon US: current deals, useful picks and tech finds.See Picks×
Skip to content
World desk4 min

How to Create an Accessible React Loading Spinner Component

A practical React spinner example with real loading state, accessible status and busy-region semantics, and reduced-motion CSS.
Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Render a spinner only while a real operation is pending, give it a text label, and make the affected content region announce that it is busy. The example below uses React state for visibility, CSS for rotation, and reduced-motion styling; it does not invent a progress percentage.

Build a spinner that follows a real loading state

This indeterminate spinner tells users that work is in progress, not how much work remains. Keep its visibility tied to the operation’s actual pending state and remove it when that operation finishes.

import { useState } from "react";
import "./LoadingPanel.css";

export default function LoadingPanel() {
  const [loading, setLoading] = useState(false);
  const [items, setItems] = useState([]);

  async function loadItems() {
    setLoading(true);
    try {
      const response = await fetch("/api/items");
      if (!response.ok) throw new Error("Could not load items");
      setItems(await response.json());
    } finally {
      setLoading(false);
    }
  }

  return (
    <section
      aria-busy={loading}
      aria-describedby={loading ? "items-loading" : undefined}
    >
      <button type="button" onClick={loadItems} disabled={loading}>
        {loading ? "Loading…" : "Load items"}
      </button>

      {loading && (
        <p id="items-loading" role="status">
          <span className="spinner" aria-hidden="true" />
          <span>Loading items…</span>
        </p>
      )}

      {!loading && items.length > 0 && (
        <ul>
          {items.map((item) => <li key={item.id}>{item.name}</li>)}
        </ul>
      )}
    </section>
  );
}

The endpoint is illustrative: replace /api/items and the displayed item fields with your own request and data. The finally block clears the busy state whether the request succeeds or throws. In a complete interface, handle the error separately so users can see how to recover; do not leave the region marked busy after the operation has ended.

Style the indicator and honor reduced motion

The circle is decorative because the adjacent text supplies the status. Hiding the visual mark from assistive technology avoids announcing a meaningless shape.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
.spinner {
  display: inline-block;
  width: 1rem;
  height: 1rem;
  margin-inline-end: 0.5rem;
  border: 2px solid currentColor;
  border-inline-end-color: transparent;
  border-radius: 50%;
  vertical-align: -0.15em;
  animation: spinner-rotate 0.8s linear infinite;
}

@keyframes spinner-rotate {
  to { transform: rotate(360deg); }
}

@media (prefers-reduced-motion: reduce) {
  .spinner {
    animation: none;
    border-inline-end-color: currentColor;
  }
}

The prefers-reduced-motion media feature detects a user preference to minimize non-essential motion. This example replaces continuous rotation with a static ring. W3C’s C39 technique describes responding to the preference to prevent CSS motion; its techniques are examples, not standalone mandatory conformance requirements. W3C: C39, Using the prefers-reduced-motion query to prevent motion.

Connect the status to the content being loaded

In the example, the status text has the ID items-loading; the section references that ID through aria-describedby while loading. The section also has aria-busy="true" only during the request. Together these attributes identify which region is being updated and communicate its busy state. Remove the description reference and clear busy status when the operation ends. WAI-ARIA Authoring Practices: Meter and progress indicators.

Rank #2
Sale
HTML and CSS: Design and Build Websites
  • HTML CSS Design and Build Web Sites
  • Comes with secure packaging
  • It can be a gift option

The text “Loading items…” is essential: the rotating mark alone does not explain what is happening. The example gives the text a role="status" so it is exposed as a status message, while the spinner itself is marked aria-hidden="true". Keep the label specific when the interface has several independent loading areas.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Choose a spinner or a progress indicator honestly

Use an indeterminate spinner when the application cannot calculate completion. If it can calculate progress, show the actual value with a progress indicator and keep the displayed and accessible values synchronized. Never attach an estimated or fabricated percentage to an indeterminate animation.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Choice When it fits Value to expose Semantics
Indeterminate spinner The operation is pending, but its completion percentage is not known. No numeric percentage; omit aria-valuenow for an indeterminate ARIA progressbar. A progressbar needs an accessible name. For a status-only message such as the example, use status text rather than claiming a measured value.
Measurable progress The application can determine real progress. The current, truthful progress value, updated as the work proceeds. Use native <progress> when its behavior and presentation suit the interface; otherwise implement the appropriate accessible progress semantics.

MDN advises using native <progress> instead of recreating its behavior with ARIA when the native element fits. An ARIA progressbar also requires an accessible name. For an indeterminate ARIA progressbar, leave out aria-valuenow; do not use that role merely to give a spinner a more technical-sounding label. MDN: ARIA progressbar role.

Rank #4
Sale
Web Design with HTML, CSS, JavaScript and jQuery Set
  • Brand: Wiley
  • Set of 2 Volumes
  • A handy two-book set that uniquely combines related technologies Highly visual format and accessible language makes these books highly effective learning tools Perfect for beginning web designers and front-end developers

Adapt the example to your interface

  • For a button action: place the status near the control or result area it describes, and keep it visible only while that action is pending.
  • For a full-page wait: provide a clear text message as well as the visual cue, and ensure the page’s busy state corresponds to the work actually underway.
  • For several independent requests: track each operation separately so one finished request does not hide another region’s indicator or clear its busy state prematurely.
  • For known progress: replace the indeterminate spinner with a value-bearing progress indicator and expose only values the application can really measure.
  • For reduced-motion users: retain a non-moving cue and status text rather than relying on rotation to signal activity.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Leave a Reply

Your email address will not be published. Required fields are marked *

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

More from the Wire

  1. World desk4 min
    How to Spot an AI Voice Scam Before Sending MoneyDon’t rely on how a caller sounds. Pause, call back through a known number, and verify the emergency with another trusted person before sending money.
  2. Mountain View desk4 min
    Google’s SynthID Detector: How to Check AI-Generated Images, Video and AudioGoogle’s SynthID Detector looks for an embedded watermark in supported images, video and audio. Here is what its results do—and do not—show.
  3. Redmond desk20 min
    How to create a link to File or Folder in Windows 11Windows 11 gives you several ways to point to a file or folder without moving or duplicating it. You can create a desktop shortcut,…
Recommended PC Tool
Recommended PC Tool
Outdated Drivers Are Slowing You DownFree scan - exact matches
PC Slower Than It Used to Be?Free scan - under a minute

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.