Spinner
Loading indicator — an inline rotating ring, or a dotted thinking-orb for waits over larger surfaces.
Default
A md spinner with the default tone (text-tertiary leading edge).
Sizes
Three sizes — xs (12px), sm (16px), and md (24px) — fit inline alongside text or inside buttons.
Tones
default uses --text-tertiary for the leading edge. primary uses the --primary brand token.
With Label
Pass a label to make the spinner meaningful to screen readers. It renders role="status" with a visually-hidden label string. Without a label the spinner is aria-hidden="true" (decorative).
Orb
variant="orb" swaps the ring for a dotted thinking-orb, drawn on a canvas by thinking-orbs. The ring belongs inline, beside a button label. The orb is for a wait over a large visual, like a card re-rendering under a scrim or an agent thinking.
The orb reuses size, mapped to the orb's own presets: xs is 20px, sm is 32px, and md is 64px. 20 and 64 are hand-tuned designs rather than a scale factor. 32 is interpolated between them.
States
Pick the animation with orb. All nine states render at every size, shown here at md, sm, and xs.
Primary tone
By default the orb's ink follows the text colour of wherever it sits. tone="primary" tints it with the --primary brand token and keeps the orb's depth shading.
Over a scrim
Because the ink follows the surrounding text colour, set the text colour on a dark scrim and the orb draws light ink in both modes. The label contract works exactly as it does for the ring.
With prefers-reduced-motion: reduce, the orb renders one still frame instead of animating. It also pauses while it is offscreen or the tab is hidden.
Installation
npx visor add spinnerThis copies three files into your project and installs thinking-orbs:
components/ui/spinner/spinner.tsx— the componentcomponents/ui/spinner/spinner-orb.tsx— the orb variant (a client component)components/ui/spinner/spinner.module.css— the styles
Usage
import { Spinner } from '@/components/ui/spinner/spinner';
{/* Decorative — inside a button */}
<Spinner size="sm" tone="primary" />
{/* Accessible — standalone loading indicator */}
<Spinner size="md" tone="primary" label="Loading data…" />
{/* Orb — a wait over a large visual */}
<Spinner variant="orb" orb="working" label="Rendering preview…" />API Reference
SpinnerProps
| Prop | Type | Default | Description |
|---|---|---|---|
size | 'xs' | 'sm' | 'md' | 'md' | Ring size. xs=12px, sm=16px, md=24px. |
tone | 'default' | 'primary' | 'default' | Color treatment for the leading edge. default uses --text-tertiary, primary uses the --primary brand token. |
label | string | — | Accessible label. When provided, renders role="status" with visually-hidden text. When omitted, aria-hidden="true" (decorative). |
The component also accepts all standard <span> HTML attributes.
Sparkline
A decorative inline SVG mini-trend chart for stat-card trend slots and dense data contexts. Zero dependencies, theme-portable stroke.
Status Dot
A 6×6px tone-tinted indicator dot. Five tones resolve from Visor semantic tokens — composes inside badges, table rows, activity feed items, and inline status text.