Line of Dots

A pure CSS loading indicator featuring five dots that sequentially grow and shrink in a left-to-right wave using box-shadow tricks — no extra elements needed.

Generated using Grepped's AI UI component generator — created from scratch, not pulled from a library.

spinnerdotswaveloaderbox-shadow

Live Preview — customize or regenerate this in the workspace

Loading preview…

Design Intent

Five dots that appear and disappear in a left-to-right wave using CSS box-shadows.

CSS

css
body { margin: 0; min-height: 100vh; display: flex; align-items: center; justify-content: center; background: #0f0f0f; }

    :root { --primary: #6366f1; }

    .line-of-dots {
      display: flex;
      align-items: center;
      justify-content: center;
    }

    .line-of-dots:before {
      animation: line-of-dots 1s infinite ease backwards;
      border-radius: 100%;
      content: '';
      height: 10px;
      transform: translate(0, -100%);
      width: 10px;
    }

    @keyframes line-of-dots {
      0%   { box-shadow: -30px 10px 0 -10px var(--primary), -15px 10px 0 -10px var(--primary), 0 10px 0 -10px var(--primary), 15px 10px 0 -10px var(--primary), 30px 10px 0 -10px var(--primary); }
      10%  { box-shadow: -30px 10px 0   0   var(--primary), -15px 10px 0 -10px var(--primary), 0 10px 0 -10px var(--primary), 15px 10px 0 -10px var(--primary), 30px 10px 0 -10px var(--primary); }
      20%  { box-shadow: -30px 10px 0   0   var(--primary), -15px 10px 0   0   var(--primary), 0 10px 0 -10px var(--primary), 15px 10px 0 -10px var(--primary), 30px 10px 0 -10px var(--primary); }
      30%  { box-shadow: -30px 10px 0   0   var(--primary), -15px 10px 0   0   var(--primary), 0 10px 0   0   var(--primary), 15px 10px 0 -10px var(--primary), 30px 10px 0 -10px var(--primary); }
      40%  { box-shadow: -30px 10px 0   0   var(--primary), -15px 10px 0   0   var(--primary), 0 10px 0   0   var(--primary), 15px 10px 0   0   var(--primary), 30px 10px 0 -10px var(--primary); }
      50%  { box-shadow: -30px 10px 0   0   var(--primary), -15px 10px 0   0   var(--primary), 0 10px 0   0   var(--primary), 15px 10px 0   0   var(--primary), 30px 10px 0   0   var(--primary); }
      60%  { box-shadow: -30px 10px 0 -10px var(--primary), -15px 10px 0   0   var(--primary), 0 10px 0   0   var(--primary), 15px 10px 0   0   var(--primary), 30px 10px 0   0   var(--primary); }
      70%  { box-shadow: -30px 10px 0 -10px var(--primary), -15px 10px 0 -10px var(--primary), 0 10px 0   0   var(--primary), 15px 10px 0   0   var(--primary), 30px 10px 0   0   var(--primary); }
      80%  { box-shadow: -30px 10px 0 -10px var(--primary), -15px 10px 0 -10px var(--primary), 0 10px 0 -10px var(--primary), 15px 10px 0   0   var(--primary), 30px 10px 0   0   var(--primary); }
      90%  { box-shadow: -30px 10px 0 -10px var(--primary), -15px 10px 0 -10px var(--primary), 0 10px 0 -10px var(--primary), 15px 10px 0 -10px var(--primary), 30px 10px 0   0   var(--primary); }
      100% { box-shadow: -30px 10px 0 -10px var(--primary), -15px 10px 0 -10px var(--primary), 0 10px 0 -10px var(--primary), 15px 10px 0 -10px var(--primary), 30px 10px 0 -10px var(--primary); }
    }

HTML

html
<div class="line-of-dots"></div>

Full Source

html
<!DOCTYPE html>
<html>
<head>
  <style>
    body { margin: 0; min-height: 100vh; display: flex; align-items: center; justify-content: center; background: #0f0f0f; }

    :root { --primary: #6366f1; }

    .line-of-dots {
      display: flex;
      align-items: center;
      justify-content: center;
    }

    .line-of-dots:before {
      animation: line-of-dots 1s infinite ease backwards;
      border-radius: 100%;
      content: '';
      height: 10px;
      transform: translate(0, -100%);
      width: 10px;
    }

    @keyframes line-of-dots {
      0%   { box-shadow: -30px 10px 0 -10px var(--primary), -15px 10px 0 -10px var(--primary), 0 10px 0 -10px var(--primary), 15px 10px 0 -10px var(--primary), 30px 10px 0 -10px var(--primary); }
      10%  { box-shadow: -30px 10px 0   0   var(--primary), -15px 10px 0 -10px var(--primary), 0 10px 0 -10px var(--primary), 15px 10px 0 -10px var(--primary), 30px 10px 0 -10px var(--primary); }
      20%  { box-shadow: -30px 10px 0   0   var(--primary), -15px 10px 0   0   var(--primary), 0 10px 0 -10px var(--primary), 15px 10px 0 -10px var(--primary), 30px 10px 0 -10px var(--primary); }
      30%  { box-shadow: -30px 10px 0   0   var(--primary), -15px 10px 0   0   var(--primary), 0 10px 0   0   var(--primary), 15px 10px 0 -10px var(--primary), 30px 10px 0 -10px var(--primary); }
      40%  { box-shadow: -30px 10px 0   0   var(--primary), -15px 10px 0   0   var(--primary), 0 10px 0   0   var(--primary), 15px 10px 0   0   var(--primary), 30px 10px 0 -10px var(--primary); }
      50%  { box-shadow: -30px 10px 0   0   var(--primary), -15px 10px 0   0   var(--primary), 0 10px 0   0   var(--primary), 15px 10px 0   0   var(--primary), 30px 10px 0   0   var(--primary); }
      60%  { box-shadow: -30px 10px 0 -10px var(--primary), -15px 10px 0   0   var(--primary), 0 10px 0   0   var(--primary), 15px 10px 0   0   var(--primary), 30px 10px 0   0   var(--primary); }
      70%  { box-shadow: -30px 10px 0 -10px var(--primary), -15px 10px 0 -10px var(--primary), 0 10px 0   0   var(--primary), 15px 10px 0   0   var(--primary), 30px 10px 0   0   var(--primary); }
      80%  { box-shadow: -30px 10px 0 -10px var(--primary), -15px 10px 0 -10px var(--primary), 0 10px 0 -10px var(--primary), 15px 10px 0   0   var(--primary), 30px 10px 0   0   var(--primary); }
      90%  { box-shadow: -30px 10px 0 -10px var(--primary), -15px 10px 0 -10px var(--primary), 0 10px 0 -10px var(--primary), 15px 10px 0 -10px var(--primary), 30px 10px 0   0   var(--primary); }
      100% { box-shadow: -30px 10px 0 -10px var(--primary), -15px 10px 0 -10px var(--primary), 0 10px 0 -10px var(--primary), 15px 10px 0 -10px var(--primary), 30px 10px 0 -10px var(--primary); }
    }
  </style>
</head>
<body>
  <div class="line-of-dots"></div>
</body>
</html>

More Spinners Animations