Spinner
Status: Experimental
Spinner communicates a short indeterminate wait through nine decorative square cells. Six presentation variants share the same loading semantics, fixed dimensions, color inheritance, and zero-JavaScript rendering.
Preview
Section titled “Preview”The default orbit variant moves a leading square around the perimeter with a fading trail while the center remains quiet.
Refreshing customers
Basic usage
Section titled “Basic usage”Pair a decorative Spinner with visible status text.
---import { Spinner } from '@freight-px/frasto';---
<span style="display:inline-flex; align-items:center; gap:.5rem;"> <Spinner /> Loading invoices</span>If visible text is not appropriate, provide label so the root becomes one polite status announcement.
<Spinner label="Loading invoices" />Variants
Section titled “Variants”Variants change presentation only. They never change loading semantics or announcement behavior.
orbit— a clockwise perimeter lead with two trail intensities.breathe— a center-out pulse through edges and corners.cascade— a diagonal intensity wave from top-left to bottom-right.counter— two opposing perimeter leads with short trails.typewriter— row-by-row reveal, hold, and gradual reset.refresh— two clockwise perimeter heads kept half a loop apart.
| Size | Dimension | Typical use |
|---|---|---|
sm |
12px |
compact buttons and table tools |
md |
16px |
inline status and default controls |
lg |
20px |
standalone local progress |
Cells and gaps scale inside the fixed root dimension, so animation never moves surrounding content.
Color and duration
Section titled “Color and duration”Spinner uses currentColor and does not infer a semantic tone. Apply color to its parent when the surrounding operation has a meaningful status.
<span style="color:var(--frasto-info);"> <Spinner variant="cascade" /> Syncing</span>
<Spinner variant="typewriter" style="--frasto-spinner-duration:2400ms;"/>--frasto-spinner-duration is an advanced presentation override. Avoid very fast cycles that make state difficult to follow.
Button loading
Section titled “Button loading”Button uses the default Orbit Spinner while preserving its label width, preventing duplicate activation, and exposing aria-busy="true" on the control.
| Prop | Type | Default | Purpose |
|---|---|---|---|
variant |
'orbit' | 'breathe' | 'cascade' | 'counter' | 'typewriter' | 'refresh' |
'orbit' |
chooses the square-matrix motion |
size |
'sm' | 'md' | 'lg' |
'md' |
fixes the indicator dimensions |
label |
string |
— | exposes the Spinner as an accessible status |
class |
string |
— | adds a consumer class |
Native span attributes are forwarded except role, aria-label, and aria-hidden, which the component owns. Use exported SpinnerVariant and SpinnerSize types when a wrapper exposes these choices.
Accessibility
Section titled “Accessibility”- All nine cells are decorative and hidden from assistive technology.
- Without
label, the Spinner root isaria-hidden="true"; pair it with visible status text or an already-labelled busy control. - With
label, the root usesrole="status"and the supplied accessible name. - Prefer one status announcement for the affected region instead of labelling several indicators.
- For a longer wait, keep explanatory text and page context visible.
Reduced motion
Section titled “Reduced motion”All six animations stop under prefers-reduced-motion. A calm static matrix with varied opacity remains visible while surrounding text or the root label continues to communicate progress.
Choosing Spinner, Skeleton, or Progress
Section titled “Choosing Spinner, Skeleton, or Progress”Use Spinner for a short local operation whose final structure is already present. Use Skeleton when initially unavailable structured content needs to reserve its eventual layout. Use a future determinate Progress component when a reliable completion value is available.