Components · Data display & feedback
Spinner
Indeterminate loading indicator. Split from zetta-feedback-v1_4.md (removed in v1.5) in v1.4.
Preview
Build with the skill
No package to install — hand this to your AI to generate or migrate the component in your stack.
Apply the Zetta "Spinner" component to this project using the zetta-design-md skill.
WHEN TO USE
- Migrating or fixing existing code (the common case): audit the current implementation against the `spinner` spec and CORRECT every deviation — replace off-spec values, don't only add new ones.
- New component: build it to the `spinner` spec in this project's stack.
AUDIT & FIX (when the component already exists)
Compare it to the skill's spec and fix, don't just append: hardcoded colors/hex, off-scale radius, wrong fonts, dark/navy fills, shadows used in place of borders (or missing borders), brand lime used as a CTA or interaction (must be primary indigo), and any missing or wrong hover / focus / active / disabled / invalid state or missing 2px focus ring. Replace each with the correct Zetta token.
ALWAYS
- Pull the authoritative spec and tokens from the skill — never guess or hardcode values.
- Use this project's own component conventions and framework idioms.
- Honor the Zetta guardrails (brand = identity only, primary = interaction, shadows for overlays) and verify in Light, Dark, and Accessibility. Anatomy & rules
◌ ← spinner-track ({colors.spinner-track}, 2px border)
◕ ← animated arc ({colors.primary}, 2px)
| State | Visual |
|---|---|
| Active | Continuously rotating arc on gray track |
| Embedded in button | Replaces button label, cursor: wait |
When to use
- Button loading state (replaces button label).
- Inline loading within a component (e.g. async validation).
- Small component-level loading where Skeleton is too complex.
When not to use
- When you know the progress percentage — use Progress Indicator.
- When loading a content area — use Skeleton.
- Page-level initial load — use Skeleton for the full layout.
Do
- Always include a visually hidden
labelprop for screen readers. - Use
cursor: waiton the parent when the spinner blocks interaction.
Don't
- Don't show a spinner for operations that complete in under 300ms — it causes flicker.
- Don't use spinner and skeleton simultaneously in the same area.
- Accessible label: "Loading…" (default) or context-specific: "Saving changes…", "Uploading file…".
- Never show the label text visually alongside the spinner — it is screen-reader only.
Keyboard
Spinner is non-interactive and has no keyboard behavior. It is a visual loading indicator only.
Accessibility
role="status"witharia-label="Loading…"(or specific label).aria-live="polite"on the container so screen readers announce when loading completes.- When embedded in a button:
aria-busy="true"on the button + visually hidden "Loading…" text.
Spec
Values and token references resolved straight from the Zetta spec.
spinner
- color
- {colors.primary}
- trackColor
- {colors.spinner-track}
- borderWidth
- 2px
- sizeSm
- 16px
- sizeMd
- 20px
- sizeLg
- 24px