Three square outlines, one inside the next, each making a full eased turn a beat after the one around it, so the set twists into a spiral and unwinds. Stock animate-spin covers it in Tailwind.
Also known as: concentric squares spinner, square spiral loader, rotating squares loader.
<div class="ldr-nested-squares" role="status" aria-label="Loading"> <span></span><span></span><span></span> </div>
.ldr-nested-squares {
--s: var(--ldr-size, 48px);
--c: var(--ldr-color, #3b82f6);
position: relative;
width: var(--s);
height: var(--s);
}
.ldr-nested-squares span {
position: absolute;
inset: 0;
border: calc(var(--s) / 12) solid var(--c);
border-radius: calc(var(--s) / 24);
animation: ldr-nested-squares-spin 1.6s cubic-bezier(0.65, 0, 0.35, 1) infinite;
}
.ldr-nested-squares span:nth-child(2) {
inset: calc(var(--s) / 6);
border-color: color-mix(in srgb, var(--ldr-color, #3b82f6) 70%, transparent);
animation-delay: 120ms;
}
.ldr-nested-squares span:nth-child(3) {
inset: calc(var(--s) / 3);
border-color: color-mix(in srgb, var(--ldr-color, #3b82f6) 40%, transparent);
animation-delay: 240ms;
}
@keyframes ldr-nested-squares-spin {
to { transform: rotate(360deg); }
}
@media (prefers-reduced-motion: reduce) {
.ldr-nested-squares, .ldr-nested-squares *, .ldr-nested-squares::before, .ldr-nested-squares::after, .ldr-nested-squares *::before, .ldr-nested-squares *::after {
animation-duration: 3s;
}
}The same loader using only Tailwind's built-in animation utilities. No custom keyframes or config needed.
<div class="relative h-12 w-12" role="status" aria-label="Loading"> <span class="absolute inset-0 animate-[spin_1.6s_cubic-bezier(0.65,0,0.35,1)_infinite] rounded-sm border-4 border-blue-500"></span> <span class="absolute inset-2 animate-[spin_1.6s_cubic-bezier(0.65,0,0.35,1)_infinite] rounded-sm border-4 border-blue-500/70 [animation-delay:120ms]"></span> <span class="absolute inset-4 animate-[spin_1.6s_cubic-bezier(0.65,0,0.35,1)_infinite] rounded-sm border-4 border-blue-500/40 [animation-delay:240ms]"></span> </div>
--ldr-color on the element or a parent.
Currently previewing #3b82f6.--ldr-size. Every dimension in the snippet is
derived from it. Currently previewing 64px.animation shorthand.
Delays on the children are relative, so they keep their rhythm.role="status" and an
aria-label so screen readers announce the wait. The reduced-motion rule
at the end slows the animation for users who asked for less motion.