Spinner
Show that work is running during a short wait.
import { Spinner } from '@youj/react'
Installation & usage
npm i @youj/reactFor an app already set up with npx @youj/cli init, which installs the peers (@youj/core, @youj/motion, motion and Base UI) and wires the provider. New app? Start at Installation.
Use a spinner for a wait of a few seconds whose length you can't measure: a sync, a lookup, a check. If you know how far along the work is, use Progress. If you know the shape of what's loading, a Skeleton holds its place. On a button, use the button's own loading state instead of placing a spinner inside it.
import { Spinner } from '@youj/react'
export function Syncing() {
return <Spinner label="Syncing issues" />
}On its own, a spinner announces its label politely. The default is "Loading". Inside something that already announces the wait, such as a loading Button or an aria-busy region with its own status, pass label={null} to keep it silent: two announcements for one wait are worse than none.
Description
An import row with a spinner, a status line and a Cancel button.
The ring at several sizes, on an accent surface and in a muted color.
size sets the ring's width and height in pixels, and defaults to 16. The stroke holds at 1.5px up to 24px, then grows with the ring. The spinner draws in currentColor, so it takes the color of the text around it, on any surface.
A domains list where a small spinner marks the domain being checked.
Next to the thing that's waiting, a small spinner can carry the status on its own. Here its label names the domain it's checking, and the short visible text is hidden from assistive technology so it isn't read twice.
Code
spinner-demo.tsx, the Demo story. The component itself comes from the package.
Reference
Propslabel, size (2)
Props
| Prop | Type | |
|---|---|---|
label | string | nullAnnounced politely. Pass | – |
size | numberRendered size in px. default 16 | 16 |
Other props pass through: extends ComponentProps<'span'>. | ||
MotionTurn, arc · reduced motion
Motion
| Moment | Tokens | ||
|---|---|---|---|
| Turna constant-rate rotation | duration.deliberateease.linear560ms · cubic-bezier(0, 0, 1, 1) · × 1.25 per turn | 560mscubic-bezier(0, 0, 1, 1)× 1.25 per turn | |
| Arcthe arc breathes between 12% and 60% of the ring | duration.deliberateease.standard560ms · cubic-bezier(0.2, 0, 0, 1) · × 2.2 per breath | 560mscubic-bezier(0.2, 0, 0, 1)× 2.2 per breath |
Reduced motion
A still quarter arc on a faint track. The label is still announced.
The turn and the breath run on different periods, so the loop never visibly repeats. It's Youj's LoaderRingIcon, so it follows the Speed control and pauses when it's offscreen or the tab is hidden.
Reduced motion
The ring stops turning and holds a quarter arc on a faint track, which still reads as "in progress". The spoken label doesn't change.
AccessibilityARIA, announcements
Accessibility
- With a
label, the spinner is astatusrole holding the label as visually hidden text, so the wait is announced politely. - With
label={null}it has no role, and its ring isaria-hidden. - Say what's happening, not just that something is. "Checking DNS for docs.youj.io" is better than "Loading".