Loading Spinner
Rotating ring indicator. Three sizes plus an optional custom color.
Preview
<LoadingSpinner /> Sizes
<LoadingSpinner size="xs" />
<LoadingSpinner size="sm" />
<LoadingSpinner size="md" />
<LoadingSpinner size="lg" /> Custom color
Pass any CSS color (including a token reference) to recolor the rotating arc.
<LoadingSpinner color="var(--color-background-utility-success, #22c55e)" />
<LoadingSpinner color="var(--color-background-utility-warning, #f59e0b)" />
<LoadingSpinner color="var(--color-background-utility-danger, #ef4444)" /> API
| Prop | Type | Default | Description |
|---|---|---|---|
size | 'xs' | 'sm' | 'md' | 'lg' | 'md' | Ring diameter (14 / 20 / 32 / 48px). |
color | string | — | Any CSS color value for the rotating arc. Defaults to --color-background-brand. |
label | string | 'Loading' | Accessible name. Say what is loading when you can — "Loading results". |
decorative | boolean | false | Hide from assistive technology entirely. For a spinner inside something that already says it is busy — an `esa-button` with `loading` (which sets `aria-busy` and keeps its own label), or an `esa-loading-overlay` that carries the message. Two names for one state is noise, not redundancy. |
Accessibility
- The ring carries
role="status"andaria-label="Loading". - Decorative-only when paired with adjacent loading text — keep one accessible name, not two.
Theming surface
Every public token this component reads, extracted from its source at build time,
split by blast radius: the hooks that belong to this component,
then the shared and system tokens it consumes alongside everything else. The
Resolves to column walks each token's real lineage —
component → semantic → primitive → raw value — so you
can see exactly where re-pointing it lands. A spoke re-skins by overriding these in
its theme-<slug>.css; component internals are never edited. No
hook for what you need? File it with /request-lego.
Wired to this component
None. This component has no hooks of its own — it themes entirely through the shared tokens below, so every override here also moves its siblings.
Shared tokens it reads
Owned by a family or by the semantic layer. Still overridable — but scope the
override (esa-foo { --form-border-color: … }) unless you mean to move
everything that reads it. Reach says what else that is.
| Token | Reach | Resolves to |
|---|---|---|
--loading-spinner-color | component +1 more | #46a758 via --color-background-brand → --color-grass-9 |
--loading-spinner-track-color | component +1 more | #d9d9d9 via --color-border-default-subtle → --color-gray-6 |
--animation-spin | semantic every component | 750ms via --duration-750 |
--radius-pill | semantic every component | 9999px via --radius-full |