Button loading spinner

On press the label fades out and an inline spinner takes its place; the button keeps its exact size.

ButtonPress Pure CSS time-based Targets: Web · App All modern browsers
Target
Implement the "Button loading spinner" effect in vanilla HTML/CSS/JS.

Context: On press the label fades out and an inline spinner takes its place; the button keeps its exact size.
Trigger: the element is pressed (pointerdown → pointerup).
Timeline: time-based (duration + easing).

Motion tokens (normal):
- opacity (label): 1 → 0
- scale (label): 1 → 0.9
- opacity (spinner): 0 → 1
- rotate (spinner): 0deg → 360deg, infinite
- duration: 180ms (swap) · 800ms per spinner turn
- easing: ease-out (swap) · linear (spin)

Motion tokens (prefers-reduced-motion):
- opacity (label): 1 → 0
- opacity (spinner): 0 → 1
- duration: 180ms
- easing: ease-out
- note: spinner still rotates (it conveys progress) but at 1.6s per turn

Technique: prefer pure CSS transitions/animations; use JS only to toggle classes.

Acceptance:
- animate only transform and opacity unless the spec lists other properties
- no layout shift; content is visible without the animation
- when prefers-reduced-motion is set, use the reduced tokens only
- button width and height do not change between states
- set aria-busy=true and disabled while loading

Generated from the spec. Prompts differ by target name only; the tokens are the source of truth.