Skip to content
Component installs need the registry setup
VegaStack Design

Spinner

An indeterminate loading indicator — a spinning lucide icon that inherits currentColor and announces itself as a status.

Status
stable
Since
0.1.0
Accessibility pattern
role=status named Loading

Last updated

Processing payment...
$100.00

Install

Configure registry credentials first using the Quickstart. Before copying this item or any transitive registry dependency, verify the signed manifest and save the exact bytes for Spinner before installation. Retain the digest printed by this command.

pnpm exec vegastack-design verify spinner

Install with the pinned shadcn CLI. Bare shadcn does not verify VegaStack signature or integrity.

pnpm dlx shadcn@4.21.0 add @vegastack/spinner

Run the exact offline --post-write command printed by the preflight, using its saved item path and independently retained --expected-integrity digest. Use the saved preflight for every transitive registry dependency too; stop on any mismatch before using the components.

Usage

import { Spinner } from "@/components/ui/spinner";

<Spinner />;
Processing payment...
$100.00

Examples

Customization

The spinner is a single lucide icon, so swapping the mark is a one-line edit to the component: the role, the accessible name and the size-4 animate-spin recipe stay where they are. The first mark below is the default, lucide Loader; the second is LoaderCircleIcon in its place.

Size

Use the size-* utility class to change the size of the spinner. It has no size prop — passing size, width or height to a lucide component is not how this system sizes icons.

Button

Add a spinner to a button to indicate a loading state. Place the spinner before the label with data-icon="inline-start" for a start position, or after the label with data-icon="inline-end" for an end position. For a pending submit that must keep its width, use the Button's own loading prop instead.

Badge

The same data-icon attributes space a spinner inside a badge.

SyncingUpdatingProcessing

Input Group

A spinner sits in an InputGroup's trailing addon (InputGroupAddon align="inline-end") to show a field resolving in place, and in a row beside a Textarea for the multi-line case.

Validating...

Empty

An Empty block is the right place for a wait long enough to need an explanation and a way out.

Processing your request
Please wait while we process your request. Do not refresh the page.

RTL

The spinner is direction-agnostic; the row around it mirrors with the document, and data-icon spacing is written in logical properties.

Processing payment...
$100.00
جاري معالجة الدفع...
١٠٠.٠٠ دولار

API Reference

Spinner adds no props of its own — it accepts everything the underlying element or Base UI primitive accepts (className, ref, ARIA attributes, event handlers).

Accessibility

  • The icon renders role="status" with aria-label="Loading", so the wait is announced once without a live region of your own.
  • When the spinner sits inside a control that already says it is busy — a Button with loading, an Item whose title reads "Processing payment…" — pass aria-label={undefined} so the state is not announced twice.
  • The colour is currentColor: the spinner inherits the ink of whatever hosts it, so it never needs a contrast decision of its own.
  • The rotation is animate-spin, one of the two sanctioned loader animations, and the global reduced-motion reset in base.css collapses it.
ContractStates tested
Behaviourdefault, empty, indeterminate, loading
Accessibilitylabeled, status-announcement
Visualdefault, loading, empty

Do / Don't

Do
Pair a spinner with the text of what is happening when the wait is longer than a moment.
Don't
Spin indefinitely with no label or timeout — a wait with no end and no explanation reads as a broken screen.

Deviations

Upstream's file plus packages/ui/upstream/patches/spinner.patch. Every hunk:

  • DOC-2 — cn is imported from @vegastack/design.
  • ICO-8 — the mark is LoaderIcon (lucide loader) in place of upstream's Loader2Icon, which is an alias of LoaderCircle. One loader shape across the system: this spinner and the Toast and Sonner loading icons are the same object spinning. The data-slot, the role="status", the aria-label and the size-4 animate-spin recipe are upstream's.

On this page