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>