Skip to content
FeedbackGenerated from the public API

Spinner

An indeterminate wait, sized to the thing it replaces.

@luc/ui

Examples

A spinner inside the control that is waiting

`loading` keeps the label, sets `aria-busy`, blocks a second press and renders a spinner with `label={null}` — so the wait is announced once, by the button.

Press one: the spinner replaces the leading edge, the label stays, and the button refuses a second press.

Five sizes

The scale is the library's own: 16 inside a control, 24 in a panel header, and nothing in between invented locally.

14

16

18

20

24

One announcement, not two

A region that is already announcing its own wait passes `label={null}`: the spinner is then a picture of the wait rather than a second live region.

Loading the last 30 days

A wait with a shape

The two are not interchangeable: a spinner says "wait", a skeleton says "this is what is coming".

Spinner · unknown length

Validating… (no estimate)

Skeleton · known shape

In a panel header, sized to its own type

Here the spinner carries the label, because nothing else on the surface says what is loading.

Positions

Refreshing positions

6 open · last refresh 12:04 UTC

Usage

import { Spinner } from "@luc/ui";
<Spinner size={18} label="Loading runs" />

Pass `label={null}` when an ancestor already announces the wait, and the spinner stops being a second live region.

Package setup — peer requirements, the stylesheet and the provider — is on installation.

API

Read from the published TypeScript API, so a prop that is not listed here does not exist and a default that is listed is the one the compiler sees.

One symbol with two props: a size from the library's own scale (14 to 24) and an optional accessible label.

Exported symbols
ExportKindSignature
Spinner2 documented props({ size, label, className, ...props }: SpinnerProps) => import("@types/react").JSX.Element

Spinner props

Type: SpinnerProps

Values the compiler reads from the declaration.

Spinner props
PropTypeDefaultNotes
label?string | null | undefined—Screen-reader text. Set to `null` when an ancestor already announces.
size?SpinnerSize | undefined—

Guidelines

Do

  • Use a spinner for a wait with no measurable end, sized to the thing it replaces: 16px inside a button, 24px in a panel.
  • Announce the wait once — a button that already says it is working passes `label={null}` to the spinner inside it.
  • Reach for a skeleton instead when the shape of the result is known, because the reader sees what is coming.

Don't

  • Do not put a spinner on every card of a page; six spinners announce six waits at the same time.
  • Do not use one for a job with a known size — a progress bar tells the reader more.
  • Do not re-implement the rotation with a custom keyframe; the component already respects reduced motion.

Accessibility

With a `label` the spinner is `role="status"` and carries that name; with `label={null}` it renders no role and no name, which is how a caller avoids a second announcement inside a control that is already busy. Under `prefers-reduced-motion` the rotation becomes a slow pulse rather than stopping, because a frozen indicator reads as a bug.

Family

Feedback

What the product says when something happened, is happening, or did not.

10 documented entries in this family. Open the family index

Luc UI v1.0Spinnerdark theme