Feedback and status

Spinner
v1.0.8
Ready for Production

A loading indicator component with smooth animation and variant options.

Prefer AI-assisted development?

This documentation is available via the Catalyst MCP Server. Learn how to connect →

Catalyst Spinner is an animated loading indicator built with a conic gradient and CSS rotation — giving you an accessible, GPU-accelerated spinner with motion-preference support out of the box.

Preview

Installation

npm install @pmi/catalyst-spinner
import { Spinner } from '@pmi/catalyst-spinner';

Variants

High Contrast

Use for better visibility on light backgrounds or in contexts where the default gradient lacks sufficient visual presence.

Preview

Sizes

The spinner defaults to size-6 (24 px). Apply any Tailwind size utility via className to scale it up or down.

Preview
size-4
size-6 (default)
size-8
size-14

Common Patterns

In a Button

Embed a small spinner inside a button to communicate a loading or processing state. The example below demonstrates the complete loading lifecycle: triggering the loading state, announcing it to assistive technologies via role="status", resolving the operation, and announcing the result via aria-live="polite".

Preview

API Reference

Prop

Type

The component also accepts all standard HTML div element attributes and forwards them to the root element.

Accessibility

Spinner is designed to meet WCAG 2.2 AA standards.

ARIA attributes

The spinner element carries no built-in ARIA role. Add role="status" and a visible or visually-hidden label so assistive technologies can announce the loading state:

<Spinner role="status" aria-label="Loading" />

For richer context, pair with visually hidden text:

<div className="relative" role="status">
  <Spinner />
  <span className="sr-only">Loading content, please wait…</span>
</div>

When the loading state resolves, role="status" carries an implicit aria-live="polite" and aria-atomic="true" — so any text updated inside that element is announced without interrupting the user. However, this live region behavior is scoped to the element's own subtree. Content that appears elsewhere in the DOM after the spinner is removed is not announced automatically. To communicate a final result or completion state, either keep a persistent role="status" element in the DOM and update its text in place, or place an aria-live="polite" region outside the spinner that remains mounted and receives the result message. See the In a Button example above for a live demonstration of this pattern.

Motion

The rotation animation uses motion-safe:animate-spin, which is suppressed for users who have enabled Reduce Motion in their system preferences (WCAG 2.2 SC 2.3.3 — Level AAA).

Choosing the Right Component

Use Spinner when the duration of the operation is unknown and no layout placeholder is available. Reach for a different primitive when:

If you need…Use instead
A content-shaped placeholder while data loadsSkeleton
A determinate progress indicator with a percentageProgress Bar
A page-level loading barLoader
A completion notification after the task finishesToast

On this page