Spinner
hc-spinner is a pure-CSS spinning ring for “busy” / pending states. It
has no JavaScript: it animates with CSS, follows currentColor by default,
and pairs with htmx’s .htmx-indicator class for request-driven
visibility.
Basic HTML
Section titled “Basic HTML”<span class="hc-spinner" role="status" aria-label="Loading"></span>The spinner inherits its indicator color from the surrounding text
(currentColor), so it sits naturally inside buttons, badges, and prose.
Set data-size="sm" or data-size="lg"; omit it for the default medium.
<span class="hc-spinner" data-size="sm" role="status" aria-label="Loading"></span><span class="hc-spinner" role="status" aria-label="Loading"></span><span class="hc-spinner" data-size="lg" role="status" aria-label="Loading"></span>Variants
Section titled “Variants”By default the indicator uses currentColor. data-variant swaps it to a
semantic accent — handy when the spinner is not inside colored text.
<span class="hc-spinner" data-variant="primary" role="status" aria-label="Loading"></span><span class="hc-spinner" data-variant="success" role="status" aria-label="Loading"></span><span class="hc-spinner" data-variant="error" role="status" aria-label="Loading"></span>| Variant | Indicator color |
|---|---|
| omitted | currentColor (inherited). |
primary | Accent / primary action. |
success | Success green. |
warning | Warning amber. |
error | Error red. |
htmx usage
Section titled “htmx usage”Add the htmx-indicator class so htmx fades the spinner in only while a
request it drives is in flight — no JS of your own. The button stays the
network owner.
<button class="hc-button" data-hx-post="/save" data-hx-disabled-elt="this"> Save <span class="hc-spinner htmx-indicator" aria-hidden="true"></span></button>Here the spinner is decorative (aria-hidden="true") because the disabled
button and the swapped response already communicate progress. When the
spinner is the only signal, give it a status name instead — see below.
Accessibility
Section titled “Accessibility”A spinner is a visual; the “busy” meaning must reach assistive tech as text. Two patterns:
-
Name the spinner itself — make it a live region with an accessible name:
<span class="hc-spinner" role="status" aria-label="Loading"></span> -
Wrap it with a visually-hidden label — keep the spinner decorative and put the text in a sibling. Use this when you want richer wording:
<span role="status"><span class="hc-spinner" aria-hidden="true"></span><span class="hc-sr-only">Loading results…</span></span>
- Reduced motion: under
prefers-reduced-motion: reducethe spin slows but does not stop — it must keep signalling that work is in progress. The accessible name keeps announcing it regardless of motion, so the status is never conveyed by animation alone. - Don’t leave an empty
role="status"with no name; an unnamed live region announces nothing.
Theming tokens
Section titled “Theming tokens”| Token path | Purpose |
|---|---|
spinner.size | Default (medium) diameter. |
spinner.sm-size / lg-size | data-size diameters. |
spinner.border-width | Ring thickness. |
spinner.track-color | The faint full ring (theme border). |
spinner.indicator-color | The leading arc (default currentColor). |
spinner.duration | One rotation duration. |
spinner.reduced-duration | Rotation under reduced motion. |
spinner.{primary,success,warning,error}-color | data-variant indicator colors. |
CSS variables
Section titled “CSS variables”Show the generated CSS variables
--hc-spinner-size | -sm-size | -lg-size--hc-spinner-border-width | -track-color | -indicator-color--hc-spinner-duration | -reduced-duration--hc-spinner-primary-color | -success-color | -warning-color | -error-color