Seven spinners, each a single element or a few small ones: two counter-rotating arcs, a segmented system-style spinner, a gradient arc like a comet, a growing and shrinking SVG arc, dots that pulse round a circle, a flipping square and one inline spinner in three sizes that takes its colour from the text.
Two arcs spin in opposite directions, one inside the other, made from borders with two transparent sides. The wrapper has role="status" with a visually hidden Loading label, which is what every spinner needs.
Twelve short bars arranged in a circle fade in sequence, the classic system activity indicator. Each bar is rotated into place with a custom property and shares one fade animation offset by a twelfth of the cycle.
A ring that fades from transparent to solid around its length, so it looks like a comet chasing its own tail. The colour is a conic gradient and the hole in the middle is a radial mask, so it is a single element.
The arc lengthens and shortens while the whole circle rotates, the material-style spinner. Two animations combine: stroke-dasharray changes the visible arc and a rotate on the svg spins it, at different durations so the pattern never quite repeats.
Eight dots on a circle grow and fade one after another, giving a rotating feel without anything actually rotating. Each dot is positioned with rotate then translate and scaled by a shared keyframe with a staggered delay.
A square that flips over its x axis, then its y axis, in a perspective space, an old favourite that still reads clearly as busy. The rotations are four keyframes, each a half turn on alternating axes.
One spinner class in three sizes, inside a button, beside text and on its own, all inheriting their colour from the surrounding text through currentColor. Size comes from the font size in em, so the spinner always matches its context.
A spinner means nothing to a screen reader. Wrap it in role="status" with a visually hidden label such as Loading results, so the wait is announced.
Use currentColor and em
Draw the spinner with currentColor and size it in em, and it automatically matches any button or line of text you put it in.
Spin with transform
Rotate with transform: rotate() and a linear timing function. Linear is the one place it is right: a spinner that eases in and out looks like it is stuttering.
When not to spin
Spinners suit waits of one to ten seconds with no known progress. For longer or measurable work, show a progress bar; for very short waits, show nothing at all to avoid a flash.
Frequently asked questions
Should spinners stop for reduced motion?
Slow them down instead. A frozen spinner can look like the page has stalled.
How is this page different from the loaders page?
Loaders covers dots, bars and skeletons; this page is rotating spinners only.
Can I use these on a dark and light background?
Yes. The inline spinner follows the text colour; the others take a single colour to change.