Skip to content

Spinner

wu-spinner is a rotating ring in the current text color. Pair it with role="status" and hidden text, or mark it aria-hidden="true" next to visible text.

Class or variable Effect
wu-spinner Root. 1.25rem ring
sm, lg 1rem ring, 2rem ring with a thicker border
--wu-spinner--Size Width and height, for every size
wu-spinner-overlay Part, last child of a busy region. Covers the region, dims its content and centers a spinner with optional text
--wu-spinner-overlay--Background Overlay tint, the surface color at 85% by default
Loading
<span class="wu-spinner" role="status"><span class="sr-only">Loading</span></span>
<div class="flex x-center gap-4">
<span class="wu-spinner sm" aria-hidden="true"></span>
<span class="wu-spinner" aria-hidden="true"></span>
<span class="wu-spinner lg" aria-hidden="true"></span>
<span class="wu-spinner" style="--wu-spinner--Size: 3rem" aria-hidden="true"></span>
</div>

The ring takes the text color of its parent.

<div class="flex x-center gap-4">
<span class="text-brand"><span class="wu-spinner" aria-hidden="true"></span></span>
<span class="text-danger"><span class="wu-spinner" aria-hidden="true"></span></span>
</div>

In a button, set aria-busy="true" instead of disabled, so the button keeps full opacity while it loads (see button loading).

Saving changes
<div class="flex wrap x-center gap-3">
<span class="flex x-center gap-2 text-muted"><span class="wu-spinner sm" aria-hidden="true"></span>Saving changes</span>
<button class="wu-btn brand" type="button" aria-busy="true"><span class="wu-spinner sm" aria-hidden="true"></span>Saving</button>
</div>

Put wu-spinner-overlay as the last child of the region that is loading: a table, a card or a form. The overlay covers the region, dims what is under it and centers the spinner and its text. The region becomes the overlay’s positioning box with position: relative, unless it already has a position of its own. The overlay adds no motion beyond the spinner’s own rotation.

Orders

Twelve orders wait for shipping.

Three need an address check.

Two were paid by bank transfer.

Loading orders
<div class="wu-card" aria-busy="true">
<div class="wu-card-body" inert>
<h3 class="wu-card-title">Orders</h3>
<p>Twelve orders wait for shipping.</p>
<p>Three need an address check.</p>
<p>Two were paid by bank transfer.</p>
</div>
<div class="wu-spinner-overlay">
<span class="wu-spinner lg" aria-hidden="true"></span>
<span>Loading orders</span>
</div>
</div>
  • Set aria-busy="true" on the region while it loads, and remove it with the overlay when the content is ready.
  • The overlay blocks pointer clicks, but not the keyboard. Put inert on the content under it, as on the card body above, so Tab skips it. Do not put inert on the region itself: that would hide the overlay text from screen readers too.
  • Keep the text short and specific (“Loading orders”). For a spinner without visible text, use role="status" and hidden text, as in the default example.

The spinner has no reduced-motion rule of its own: core’s reset stops animations when reduced motion is set, so the ring stands still.

@use "@wovenui/components/spinner";

The spinner needs no other component. The examples above also use the button and the card.