Spin

A loading indicator, on its own or wrapped around the content it is waiting for, with a delay so a fast response never flashes it.

Usage

When to use a spinner instead of a skeleton or a progress bar, whether to wrap content, how long to wait before showing it, and when to add words.

When to use

Spin says that something is happening, with no number on it. Use it when the wait is short, cannot be measured, and the reader has nothing to do but wait.
  • A region is refetching and you do not know the shape of what comes back: a chart, search results, a panel that depends on the answer.
  • A whole route or a modal is waiting on one request, which is the fullscreen case.
  • A short wait beside a label, where a skeleton would be bigger than the thing it stands in for.
Use something else when:
  • You know the shape of the content. Use Skeleton. Grayed-out rows or cards show what is coming and keep the layout from jumping when it lands.
  • You can measure the work. Use Progress. If you can say 40%, say 40%.
  • The wait belongs to one control. Use its own loading prop. A Button that spins in place keeps its label and position and disables itself. A Spin around a button only dims it, which reads as broken.

Standalone, or wrapping children

Whether you nest anything in Spin changes what it does.
  • <Spin /> with nothing inside is a bare indicator. Center it with its parent.
  • <Spin spinning={loading}>...</Spin> around content keeps the content in place, dims it, shows the spinner on top and blocks clicks on it. Nothing around it moves.
Wrap the smallest region that is out of date. A Spin around a whole page dims the navigation the reader might use to leave.
spinning defaults to true, so <Spin>{children}</Spin> without spinning stays loading forever. Always pass it when you wrap content.

Delay, so a fast response never flashes

delay is how many milliseconds to wait before showing the spinner, and it defaults to 0. A spinner that appears and vanishes within a moment reads as a glitch.
  • Add a delay to anything that is usually fast: a cached query, a local filter. Try 300 to 500ms against your own response times.
  • If the request finishes before the delay runs out, the spinner never shows at all.
  • Leave it off when the wait is always long. A one second request with a 500ms delay gives the reader half a second of nothing.

When a wait needs words

description shows a line of text under the spinner. Dots say “wait”, not what for, how long, or whether it is safe to leave.
  • Add words when the wait is long or unusual, or when leaving would lose work. “Importing 2,400 rows” beats a silent spinner.
  • Name the work, not the mechanism. “Loading” repeats the dots, and an API path means nothing to the reader.
  • Only show a countdown or a percentage when you know the number.
  • Write description, not tip. tip is deprecated and logs a warning. The text shows with or without children.

Size, and the indicator itself

size is small, medium or large. Leave it off for medium. size="default" is deprecated and logs a warning.
  • small beside text or in a table cell, medium over a region, large when the spinner is the only thing on the surface.
  • The default dots are CSS, not an icon, so they look the same with any icon pack.
  • A pack icon needs animate-spin. Pass your own glyph to indicator, like <Icon name="loading" className="animate-spin" />. The icon does not spin on its own.
  • Recolor the dots with classNames.section. Pass it a text color class. On a Spin with no children, className works too, but once it wraps content only classNames.section reaches the dots.
  • Set one indicator for the whole app with spin on ConfigProvider instead of repeating it.

The percent ring

percent draws a ring around the dots. A number shows that number. auto fills the ring slower and slower without reaching 100, and only moves while spinning is true.
  • Pass a number only when you have a real one. The ring reads as a measurement.
  • Use auto when you have no number but the wait is long enough that it should feel bounded. Do not put a figure beside it.
  • For a real job with a real number, use Progress, which can show the value as text.
  • The kit draws the ring thinner than Ant Design does. Change the stroke with your own class, like [&_.ant-spin-dot-circle]:[stroke-width:6], but never the circle's r, which makes the ring show the wrong percentage.

Fullscreen

fullscreen covers the whole page with a mask and a centered spinner, and ignores children. Save it for the biggest waits.
  • Use it when the whole screen cannot be used: a route change that replaces everything, a submit that must not be interrupted. A region that is refetching should wrap only that region.
  • Give a fullscreen spinner an end. It covers the whole page and has nothing to click, so turn spinning off from code when the work is done. A request that can hang needs a timeout, a cancel or an error state.
  • Add a description. A blank, dimmed screen is where the reader most needs to know what is happening.