Diwa Design System

Spinner

A CSS-only animated loading indicator. Communicates asynchronous activity to both sighted users and screen readers via role="status" and an accessible label.

Keyboard interaction

The spinner is a non-interactive status indicator. It receives no keyboard focus and has no keyboard interactions.

KeyAction
No keyboard interaction. The spinner is a display-only live region.

Screen reader behaviour

The following ARIA attributes are managed internally by the component:

Attribute / PropertyValue / Behaviour
role="status"Applied to the host element. Creates a polite live region — screen readers will announce the label when the spinner enters the DOM without stealing focus.
aria-labelBound to the label prop. Provides the announcement text. Defaults to "Loading". Override with a descriptive value such as "Saving changes" or "Uploading file".
aria-hidden="true"Applied to the inner ring element. Hides the purely decorative SVG ring from the accessibility tree — only the host-level role and label are exposed.

Best practices

  • Live region behaviourrole="status" is a polite live region. The announcement is queued behind the current speech, preventing interruption. If you need an assertive announcement (e.g. an error state spinner), wrap the spinner in an element with aria-live="assertive".
  • Reduced motion — the spinner respects prefers-reduced-motion. When enabled, the rotation animation is suppressed.
  • Colour contrast — the spinner stroke inherits currentColor. Ensure the surrounding text colour meets the 3:1 WCAG AA contrast requirement for non-text elements against the background.
  • Label specificity — always provide a meaningful label prop that describes the operation in progress. Avoid the generic default when users can benefit from more context.

WCAG 2.2 compliance

1.4.3 Contrast (Minimum) — AAPass

The spinner stroke uses currentColor, inheriting from the surrounding text. Ensure the surrounding colour meets the 4.5:1 minimum ratio.

1.4.11 Non-text Contrast — AAPass

As a non-text graphic element, the ring requires ≥ 3:1 contrast against the background. currentColor ensures this when the parent text colour meets AA.

1.4.5 Images of Text — AAPass

No text is rendered as an image. The label is a genuine text node exposed via aria-label.

2.1.1 Keyboard — APass

The spinner is non-interactive and receives no keyboard focus. No keyboard operation is required.

4.1.3 Status Messages — AAPass

role="status" creates a polite live region. Screen readers announce the label when the spinner enters the DOM without requiring focus.