No pulsing attention loops
Status dots and CTAs stay still; a color and a word carry the state.
From design-motion-principles, anti-checklist, Pulsing indicators.
Six services, one goes down
Break a service. Which pane shows the outage first?
Every dot pulsesBad
animation: pulse 2s infiniteStatic dot + labelGood
animation: none.status { display: inline-flex; align-items: center; gap: 6px; }
.status::before {
content: ""; width: 8px; height: 8px; border-radius: 50%;
background: currentColor;
}
.status[data-state="ok"] { color: var(--good); }
.status[data-state="down"] { color: var(--bad); font-weight: 600; }
<span class="status" data-state="down">Down</span>
Breathing CTA vs static button
Type a name in each pane. Where does your eye go?
Breathes foreverBad
animation: breathe 2s ease-in-out infiniteEnables when readyGood
button.disabled = !valid.btn-primary {
background: var(--accent); color: var(--accent-ink);
transition: transform 160ms var(--ease-out), background-color 150ms ease;
}
.btn-primary:active { transform: scale(0.97); }
.btn-primary:disabled { opacity: .5; }
input.addEventListener("input", () => {
button.disabled = input.value.trim() === "";
});
Let the data prove it's live
Press Record, then Stall the stream.
Pulsing ringBad
Not recording
animation: ping 1s infiniteStatic dot + timerGood
REC 00:00
time.textContent = fmt(elapsed).rec-dot { width: 10px; height: 10px; border-radius: 50%; background: var(--bad); }
.rec[data-state="stalled"] .rec-dot { background: var(--warn); }
.rec-time { font-variant-numeric: tabular-nums; }
stream.on("chunk", (c) => {
elapsed += c.duration;
time.textContent = fmt(elapsed);
lastChunk = performance.now();
});
setInterval(() => {
rec.dataset.state = performance.now() - lastChunk > 2000 ? "stalled" : "live";
}, 500);
Why it matters, pros and cons
Why it matters
A loop that never stops means nothing, and still says “live” after data dies.
Pros
- Real changes get the contrast
- Nothing to pause for WCAG 2.2.2
- Liveness proven by data, not decoration
Cons
- One brand element with a written reason may pulse
- A one-shot pulse on a new event is fine
- Needs a label or shape, not color alone