Loading is a decorative SVG indicator for operations that are in flight. It
ships in two flavors: a segmented spinner that fades through eight positions,
and three dots that pulse in sequence. Both inherit currentColor, so they
pick up the text color of whatever they sit inside.
Reach for <Loading> when you need a freestanding progress mark — inside a
table cell, next to a row label, in an empty state while data streams in.
<Button loading> already embeds a spinner with all the ARIA wiring; use
this component when there is no button to hang the spinner on.
Import
import { Loading } from "@unkey/ui";
Spinner
The default type. Eight segments rotate clockwise, each fading in and out
to imply motion. Good for open-ended waits where you can’t show a percentage.
Dots
Set type="dots" for three horizontally-arranged circles that contract and
expand in sequence. The dots read as softer than the spinner and work well in
dense tabular contexts where a spinning ring would draw too much attention.
Size
size is a number in pixels and sets both width and height. The spinner
defaults to 18, the dots to 24. Scale up for hero empty states, scale
down to sit alongside small body copy.
Duration
duration accepts a CSS time string — either "124ms" or "0.75s". For the
spinner, it controls the time each segment holds before the next lights up
(default is ~125ms per segment, so one full rotation takes roughly one
second). For dots, it’s the total cycle length of a single pulse (default
"0.75s").
A shorter duration reads as “working hard”; a longer one reads as “patiently waiting”. Match the perceived urgency of the underlying task, and avoid durations so short that the motion becomes a distraction.
Accessibility
<Loading> renders a bare, unlabeled <svg>. Screen readers will not
announce it on their own. When the indicator represents a real
in-flight operation, pair it with a sibling element that carries the
semantics:
- Mark the region that is loading with
aria-busy="true"so assistive tech knows its contents are stale. - Add an
sr-onlylabel that names what is loading —"Loading API keys","Fetching logs"— next to the spinner. A generic “loading” is rarely enough. - The spinner honors
prefers-reduced-motionvia theanimate-spin-slowutility. The dots animation uses SMIL and pauses accordingly in browsers that respect the preference.
If the indicator is purely ornamental (e.g. a placeholder glyph during a
skeleton render), leave it unlabeled — an empty aria-hidden="true" on a
wrapping element is enough.
Props
type "spinner" | "dots" Optional
Default "spinner" Which indicator to render. spinner is the eight-segment rotating ring,
dots is three horizontal pulsing circles.
size number Optional
Default 18 (spinner), 24 (dots) Width and height in pixels. The SVG scales uniformly; use whole numbers that match the font size of neighboring text.
duration string Optional Animation timing as a CSS time string ("124ms" or "0.75s"). For the
spinner, this is the dwell time per segment. For dots, it’s the total
cycle length of one pulse.
className string Optional Additional Tailwind classes. Merged with fill-current so the indicator
inherits text color from its parent.
...rest SVGProps<SVGSVGElement> Optional All standard SVG attributes (role, aria-label, style, etc.) pass
through to the underlying <svg>.
Related
- Button — use
<Button loading>when the indicator belongs to a button press; it embeds this spinner plus the requiredaria-busywiring. - Alert — for states where the wait is long enough to warrant an explanation, not just a spinner.