Loading indicators that announce themselves

A bare spinning div is invisible to a screen reader. These come with the role and the name that make them mean something.

HomeProfessionsDesign › Spinners

Loading indicators that announce themselves

A bare spinning div is invisible to a screen reader. Every spinner here comes with the role and the accessible name that make it mean something.

Local tool — nothing you make here is uploaded
Nothing here leaves this browser. Colours, images, SVG and generated code are processed on your own device. No file is uploaded, nothing you enter is stored on a server, and none of it is passed to the analytics or advertising scripts on this page.
What a contrast check does and does not prove. Meeting a ratio satisfies one WCAG success criterion. It does not make an interface accessible, and it says nothing about focus order, labelling, motion, or whether the thing is usable at all. Automated checks find a minority of real barriers.
Reduced motion: slower, not stopped

Stopping the animation entirely leaves a shape that looks like a frozen page, which is worse than no indicator. Slowing it to two and a half seconds keeps the signal and removes the fast repetitive motion that causes the problem.

WCAG 2.2.2 only requires that motion lasting more than five seconds can be paused, so a spinner is technically compliant either way. Respecting the preference anyway costs one media query.

role="status" makes the region a live region with a polite announcement. Without an accessible name it announces nothing useful, so aria-label="Loading" is not optional.

A spinner is an admission

It says the interface does not know how long this will take. Where you do know — a file upload, a multi-step process — a progress bar tells the user far more, and where the wait is short a skeleton preserves the layout instead of replacing it.

Spinners are right for genuinely indeterminate waits, and they are used far more widely than that.

Do not show one immediately

A spinner that appears and disappears within 200 milliseconds reads as a flicker and makes the interface feel less stable, not more responsive. Delaying it by around 300ms means fast responses never show one at all.