GitHub

Loading Spinner

Rotating ring indicator. Three sizes plus an optional custom color.

Stable .astro import EsaLoadingSpinner from '@esa/ecology/esa-loading-spinner.astro';

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

PropTypeDefaultDescription
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" and aria-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