Spinner
An animated icon that shows an operation is in progress when its duration is unknown.
@zenoxai/ui/components/spinner Markdownfunction SpinnerDemo() {
return <Spinner />
}Usage
import { Spinner } from "@zenoxai/ui/components/spinner"
export function TimelineLoading() {
return (
<div className="flex h-40 items-center justify-center">
<Spinner aria-label="Loading threat timeline" />
</div>
)
}
Use a spinner for a short wait with no measurable progress: a button action, a panel that is fetching. Pick the alternative that tells the user more when there is one:
- The layout of the content is known in advance (a table, a card): use a Skeleton, which avoids a jump when the content arrives.
- The operation reports how far along it is (an export, an upload): use a Progress bar.
Spinner is a Loader2 icon from lucide-react that spins. It takes every SVG prop. It
inherits the text color and is 16px by default; change both with classes.
Examples
Sizes
Size the spinner to the text or the space around it: size-3 next to small text, the default
16px in buttons and inputs, size-6 or size-8 for a panel or a page.
<>
<Spinner className="size-3" />
<Spinner />
<Spinner className="size-6" />
<Spinner className="size-8 text-primary" />
</>In a button
Put the spinner in place of the button’s icon with data-icon="inline-start", keep the label,
and disable the button until the action ends. Hide the spinner from screen readers with
aria-hidden: the label already says what is happening.
<>
<Button disabled>
<Spinner data-icon="inline-start" aria-hidden />
Scanning
</Button>
<Button variant="outline" size="sm" disabled>
<Spinner data-icon="inline-start" aria-hidden />
Exporting report
</Button>
</>With a label
A spinner next to text that names what is loading. The text carries the meaning, so the
spinner is hidden from screen readers. Keep the role="status" element mounted and change its
text when the wait ends (“Loaded 128 assets”), so screen readers announce the result.
<div className="flex items-center gap-2 text-sm text-text-secondary">
<Spinner aria-hidden />
<span role="status">Loading assets for Acme Corp</span>
</div>In a panel
Center a larger spinner in the space the content will take, with a fixed height so the layout
does not jump. Without visible text, set an aria-label that names what is loading.
<div className="flex h-40 w-full max-w-sm items-center justify-center rounded-lg border border-border-subtle bg-surface-muted">
<Spinner
className="size-6 text-text-muted"
aria-label="Loading threat timeline"
/>
</div>Accessibility
- The spinner renders
role="status"witharia-label="Loading". Replace the label with what is loading (“Loading threat timeline”) when the spinner stands alone. - Inside a button, set
aria-hidden. Otherwise “Loading” becomes part of the button’s accessible name (“Loading Scanning”). - A status region added to the page together with its content is often not announced. When
the end of the wait matters, announce it from a
role="status"element that is already on the page, or with a toast. - The animation stops for users who ask for reduced motion; the icon stays visible.
API reference
Generated from the TypeScript source. className, style and children are accepted everywhere and omitted below.
Spinner
Spinner is a rotating loader for an action in progress, such as a button waiting for the server. For content that is loading, prefer a Skeleton in its shape.
No props of its own. Accepts the props of the element it renders.