Spinner
import { Spinner } from '@absoluteui/components/spinner';import '@absoluteui/components/spinner/style.css';Using Angular? See Spinner for Angular.
What it does
Section titled “What it does”An indeterminate loading indicator. The host is a role="status" region (implicitly aria-live="polite") containing a decorative rotating icon and a localized label. It provides:
- a label that is announced politely when the spinner appears;
- an optional
delay, so fast operations never flash a spinner; - a static icon under reduced motion.
When to use
Section titled “When to use”- Short waits of unknown duration (loading a panel, saving).
- Inside a busy region (aria-busy) as the announced status next to Skeleton placeholders.
When not to use
Section titled “When not to use”- Measurable progress: use ProgressBar.
- Blocking the whole page: prefer skeletons or inline progress.
- Inside buttons as the only feedback without a label.
Examples
Section titled “Examples”Delayed spinner for a fetch
Section titled “Delayed spinner for a fetch”import { Spinner } from '@absoluteui/components/spinner';
const host = document.querySelector<HTMLElement>('#results-status');if (host) { const spinner = Spinner.create(host, { label: 'Loading results', delay: 300 }); void fetch('/api/results').finally(() => { spinner.destroy(); });}Visible label, small size
Section titled “Visible label, small size”import { Spinner } from '@absoluteui/components/spinner';
const host = document.querySelector<HTMLElement>('#saving');if (host) { Spinner.create(host, { label: 'Saving changes', showLabel: true, size: 'sm' });}import { Spinner } from '@absoluteui/components/spinner';import '@absoluteui/components/spinner/style.css';
const host = document.querySelector<HTMLElement>('#saving');if (host) { const spinner = Spinner.create(host, { label: 'Saving changes', showLabel: true, delay: 200 }); void fetch('/api/save', { method: 'POST' }).finally(() => { spinner.destroy(); });}More usage
Section titled “More usage”import { Spinner } from '@absoluteui/components/spinner';
const host = document.createElement('div');document.body.append(host);const spinner = Spinner.create(host, { label: 'Loading results', delay: 300 });spinner.destroy();Anatomy
Section titled “Anatomy”<div class="aui-spinner aui-spinner--{size} [aui-spinner--pending]" role="status"> <svg class="aui-icon aui-spinner__icon" aria-hidden="true"></svg> (after the delay) <span class="aui-spinner__label [aui-spinner__label--hidden]">Loading</span></div>API reference
Section titled “API reference”Factory
Section titled “Factory”Spinner.create(host: HTMLElement, options?: SpinnerOptions): SpinnerGlobal configuration key: spinner (see Configuration).
Options
Section titled “Options”| Option | Type | Default | Description |
|---|---|---|---|
label |
string |
Announced (and optionally visible) label. Default: localized “Loading”. | |
showLabel |
boolean |
false |
Show the label visibly; otherwise it is visually hidden but announced. |
icons |
Partial<{ spinner: IconRef }> |
Icon slot overrides. | |
size |
'sm' | 'md' | 'lg' |
"md" |
Icon size. Globally configurable. |
delay |
number |
0 |
Milliseconds (integer 0..60000) before the content is shown. Globally configurable. Set at creation only. |
locale |
string |
"en-US" |
Message locale for the default label. Globally configurable. Inherited from common configuration. |
Properties
Section titled “Properties”| Property | Type | Description |
|---|---|---|
host |
HTMLElement |
The role=“status” host. |
visible |
boolean |
Whether the delay elapsed and content is rendered. |
Methods
Section titled “Methods”| Method | Description |
|---|---|
update(options: Partial<SpinnerOptions>): void |
Merge and apply options (delay cannot change). |
destroy(): void |
Cancel a pending delay; remove rendering, role, and subscriptions. |
CSS classes
Section titled “CSS classes”All rules live in the aui.components cascade layer, so application styles override them without specificity battles.
| Class | Purpose |
|---|---|
aui-spinner |
Host (role=“status”). |
aui-spinner--sm | --md | --lg |
Size modifiers. |
aui-spinner--pending |
Delay not yet elapsed. |
aui-spinner__icon |
Decorative rotating icon (aria-hidden). |
aui-spinner__label |
Label text. |
aui-spinner__label--hidden |
Visually hidden label. |
Icon slots
Section titled “Icon slots”| Slot | Default icon |
|---|---|
spinner |
spinner |
Design tokens
Section titled “Design tokens”Tokens this stylesheet reads (verified in CI). Override them in a theme or with the Theme Designer.
--aui-color-primary | --aui-color-text | --aui-font-family-sans | --aui-font-size-sm | --aui-icon-size-lg | --aui-icon-size-md | --aui-icon-size-sm | --aui-line-height-tight | --aui-space-2
TypeScript definitions
Section titled “TypeScript definitions”type SpinnerSize = 'sm' | 'md' | 'lg';interface SpinnerIcons { spinner: IconRef }interface SpinnerConfig { size: SpinnerSize; delay: number }interface SpinnerOptions extends Partial<SpinnerConfig> { label?: string; showLabel?: boolean; locale?: string; icons?: Partial<SpinnerIcons>;}Accessibility
Section titled “Accessibility”Pattern: ARIA status live region (role=“status”, implicit aria-live=“polite”).
Keyboard
Section titled “Keyboard”| Key | Context | Action |
|---|---|---|
| None | Any | Not focusable; no keyboard interaction. |
| Element | Role |
|---|---|
| host | status |
| icon | none (aria-hidden=true) |
ARIA attributes
Section titled “ARIA attributes”| Attribute | Element | Value |
|---|---|---|
role |
host | status |
aria-hidden |
icon | true |
Not focusable. Focus is never moved.
WCAG 2.2 success criteria addressed
Section titled “WCAG 2.2 success criteria addressed”| Criterion | Level | Note |
|---|---|---|
| 1.3.1 Info and Relationships | A | |
| 2.2.2 Pause, Stop, Hide | A | |
| 2.3.3 Animation from Interactions | AAA | |
| 4.1.3 Status Messages | AA |
Automated test results: Accessibility and compliance.
Notes and known caveats
Section titled “Notes and known caveats”- The status region is rendered empty until the delay elapses; inserting the label then triggers a polite announcement.
- Rotation stops under prefers-reduced-motion or animation: none; the static icon and the label remain.
- The label is visually hidden by default and always remains in the accessibility tree.
- Manual screen-reader verification (NVDA, JAWS, VoiceOver) is pending.
Behavior
Section titled “Behavior”States
Section titled “States”pending (the delay has not elapsed; the status region is empty) and visible.
State transitions
Section titled “State transitions”| From | Trigger | To |
|---|---|---|
(created, delay: 0) |
create |
visible |
(created, delay > 0) |
create |
pending |
| pending | delay elapses | visible (label inserted and announced) |
| pending / visible | destroy() |
removed; a pending timer is cancelled |
Accessibility notes
Section titled “Accessibility notes”- The region exists from creation and is empty while pending. Inserting the label into the existing region triggers a polite announcement.
- With
delay: 0the region and its content appear in the same task, and some screen readers may not announce it. Use a delay, or create the spinner on an empty host that is already in the page. - Rotation stops under
prefers-reduced-motion: reduceoranimation: 'none'. The static icon and the label remain. - Manual screen-reader verification is pending.
Responsive behavior
Section titled “Responsive behavior”Inline-level. The icon size follows size; the visible label wraps with the surrounding text.
Right-to-left
Section titled “Right-to-left”Logical gap between the icon and the label. The rotation direction is not mirrored.
Theming
Section titled “Theming”The icon uses color-primary and the label uses color-text. Forced-colors mode uses CanvasText.
Global configuration
Section titled “Global configuration”configureAbsoluteUI({ components: { spinner: { size: 'sm', delay: 300 } } });size applies to existing instances immediately; delay applies to new instances.
Component configuration
Section titled “Component configuration”Instance options override global and theme defaults. delay is init-only; all other options are dynamic.
icons.spinner (default spinner).
Security
Section titled “Security”The label uses textContent. No inline styles; the visually hidden label uses a CSS class.
Data handling
Section titled “Data handling”No persistence, network access, or telemetry.
Performance
Section titled “Performance”No DOM listeners; one timer while pending and one configuration subscription. The rotation is a compositor-friendly transform animation. Target: under 1 ms per Spinner.create in headless Chromium (not yet covered by the e2e performance suite).
Supported data scale
Section titled “Supported data scale”One spinner per loading region. Many simultaneous spinners are an anti-pattern, because each one is a live region.
Edge cases
Section titled “Edge cases”- Destroying the spinner before the delay elapses means it never renders, which is the intended behavior for fast operations.
- Changing the label while visible updates the region text, and screen readers announce the new label.
- The default label follows the configured locale; register translations with
registerMessages('spinner', locale, { loading }).
Errors
Section titled “Errors”| Code | Category | Cause |
|---|---|---|
SPINNER_OPTIONS |
configuration | Empty label. |
CFG_INVALID_VALUE |
configuration | Invalid size, or delay outside 0-60000 or not an integer. |
CFG_INIT_ONLY |
configuration | update({ delay }) on an existing instance. |
A failed construction leaves the host untouched.
Known limitations
Section titled “Known limitations”- The announcement for
delay: 0depends on the screen reader (see Accessibility notes). delayis init-only.- Manual screen-reader verification is pending.
Unsupported scenarios
Section titled “Unsupported scenarios”- Determinate progress.
- HTML in the label.