Skip to content
All designer tools

Loader Generator

Spinners, dots, bars and pulses as pure CSS — tuned on sliders, seeded from the 35 loaders already in the catalog, and emitted with the reduced-motion guard and the status role that hand-written ones go without

Ring

Loading…

The default spinner: a border with one coloured side, rotated. Four declarations, works everywhere, and the one people recognise as "loading".

htmlHTML
<div class="loader" role="status"><span class="loader-label">Loading…</span></div>
jsxJSX
<div className="loader" role="status"><span className="loader-label">Loading…</span></div>
cssCSS
.loader {
  position: relative;
  display: inline-block;
  width: 40px;
  height: 40px;
  border: 4px solid rgba(79, 70, 229, 0.2);
  border-top-color: #4f46e5;
  border-radius: 50%;
  animation: loader-anim 1s linear infinite;
}

@keyframes loader-anim {
  to { transform: rotate(360deg); }
}

.loader-label {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

@media (prefers-reduced-motion: reduce) {
  .loader,
  .loader::before,
  .loader::after,
  .loader *,
  .loader *::before,
  .loader *::after {
    animation-duration: 1ms !important;
    animation-iteration-count: 1 !important;
    animation-delay: 0ms !important;
    transition-duration: 1ms !important;
    transition-delay: 0ms !important;
  }
}

What ships with it

  • A reduced-motion guard. Every loader here animates forever, which is exactly whatprefers-reduced-motionexists to stop. The guard collapses the duration rather than setting animation: none, so the loader ends on its final keyframe instead of vanishing.
  • A status role and a name. role="status" plus a visually-hidden “Loading…”, so the interval where sighted users are told to wait is not silence for everyone else.
  • Keyframes named after your class. loader-anim. Keyframe names are global — two loaders sharing one means the second stylesheet silently redefines the first.

Start from one of the 42 in the catalog

See them all

These are the real entries, running. Picking one reads its own stylesheet — size, thickness, duration, colour, how many parts it has — and opens the sliders on those numbers. It lands on the nearest family rather than reproducing the original exactly; for the exact CSS, open the effect.

  • Classic Spinner

  • Three Dots Bounce

  • Pulse Ring Loader

  • Square Wave

  • Skeleton Shimmer

  • Indeterminate Bar

  • Orbit Loader

  • Liquid Wave Loader

  • Hexagon Flip Loader

  • Gradient Ring Loader

  • Blue Ring Spinner (Norm)

  • Ocean Bouncing Dots (Norm)

  • Blue Pulse Heartbeat (Norm)

  • Ocean Equalizer Bars (Norm)

  • Ocean Dual-Ring Spinner (MD)

  • Ocean Conic Ring Spinner

  • Blue Equalizer Loader

  • Ocean Morphing Dots

  • Ocean Masked Ring Loader

  • Ocean Percentage Ring

  • Ocean Orbit Loader

  • Ocean Upload Loader

  • Ocean Liquid Loader

  • Ocean Typing Indicator

  • Ocean Build Log

  • Ocean Infinity Loader

  • Ocean Folding Cube

  • Ocean Newton's Cradle

  • Sliding Tiles Loader

  • Helix Strand Loader

  • Radar Sweep Loader

  • Coin Flip Loader

  • Rolling Ball Loader

  • Ping Ripple Loader

  • Domino Fall Loader

  • Snake Grid Loader

  • Tick Spinner Loader

  • Stacking Blocks Loader

  • Gear Train Loader

  • Abacus Count Loader

  • Piston Pump Loader

  • Circuit Trace Loader

Now use it on something

Every effect, block, page and template in the catalog is styled against tokens shaped exactly like these — so they take your values rather than fighting them.

npx shadcn@latest add https://hoverlab.dev/r/hoverlab.json

Size40px

One number sizes the whole thing — dots, orbit radius and stroke inset are all derived from it. A loader with nine independent measurements is one nobody gets right.

Thickness4px

Border, stroke or bar width. Below about 2px a spinner disappears on a low-DPI screen; above about a tenth of the size it stops reading as a ring.

Speed1.0s

One full cycle. Under about 0.6s a spinner reads as frantic and makes a wait feel broken; over about 2s it reads as stalled.

The lit part

A full CSS colour rather than a picker, because this one is almost always translucent — a track at 20% of the loader colour sits correctly on any surface, which an opaque grey does not.

Everything is namespaced to it, keyframes included, so two loaders from this tool can live in one stylesheet.

What a screen reader says when this appears. Name the operation — “Saving changes” beats “Loading”.

Keep this loader. This browser remembers what you last had open. A free account remembers the ones you name, on every machine you use.

More designer tools

All 36 run in the tab — no account, no upload.See all