Spinner

Signals indeterminate progress. 16px ring with a 1px stroke; respects reduced motion.

Now

Composing

The press is still. One mark turns.

Use it for

  • Short waits of unknown length inside a control or a row.
  • label to say what is loading.

Not for

  • Known progress; use Progress.
  • Whole-page waits; use Skeleton.

Three ways in. They share one source, so the pixels match whichever you pick.

1. Import the package

npm install @noorddev/vlak-react

// once, next to your app's root
import "@noorddev/vlak-react/css";

import { Spinner } from "@noorddev/vlak-react";

Precompiled React and one stylesheet. No compiler to configure. Per-component imports work too: @noorddev/vlak-react/components/spinner.

2. Vendor the source

npx @noorddev/vlak-cli add spinner

The StyleX leaf lands in components/vlak/, for your own compiler to own. See StyleX.

3. Through shadcn

npx shadcn add https://vlak.dev/r/spinner.json

The same registry item, installed by shadcn's CLI.

CSS only

<link rel="stylesheet" href="node_modules/@noorddev/vlak/css/vlak.css" />

No React. Link vlak.css and use the markup and classes below.

import { Spinner } from "@noorddev/vlak-react";

<Spinner label="Loading" />

Spinner

Hairline ring. Stops under prefers-reduced-motion.

PropTypeDefaultDescription
labelstring"Loading"

Also accepts HTMLAttributes<HTMLSpanElement>.

<span class="rs-spinner" role="status" aria-label="Loading"><svg viewBox="0 0 16 16" width="16" height="16" fill="none"><circle cx="8" cy="8" r="6.5" stroke="currentColor" stroke-width="1" stroke-linecap="butt" stroke-linejoin="miter" stroke-dasharray="28 13" vector-effect="non-scaling-stroke"/></svg></span>
.rs-spinner.rs-spinner-ring