Pulse Dots Loader
Three dots that rise and fade in turn. Tiny, calm and accessible.
Preview and code
index.html
<span class="pd" role="status"><i></i><i></i><i></i><span class="pd__sr">Loading</span></span>
styles.css
.pd{display:inline-flex;gap:8px}
.pd i{width:12px;height:12px;border-radius:50%;background:var(--accent);animation:pd 1s ease-in-out infinite}
.pd i:nth-child(2){animation-delay:.15s}.pd i:nth-child(3){animation-delay:.3s}
.pd__sr{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0)}
@keyframes pd{0%,80%,100%{transform:translateY(0);opacity:.35}40%{transform:translateY(-10px);opacity:1}}
@media (prefers-reduced-motion:reduce){.pd i{animation-duration:2.4s}}
pulse-dots-loader.tsx
const css = `
.pd{display:inline-flex;gap:8px}
.pd i{width:12px;height:12px;border-radius:50%;background:var(--pd-color,#1659f5);animation:pd 1s ease-in-out infinite}
.pd i:nth-child(2){animation-delay:.15s}.pd i:nth-child(3){animation-delay:.3s}
.pd__sr{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0)}
@keyframes pd{0%,80%,100%{transform:translateY(0);opacity:.35}40%{transform:translateY(-10px);opacity:1}}
@media (prefers-reduced-motion:reduce){.pd i{animation-duration:2.4s}}`;
export function PulseDots({ color = "#1659f5", label = "Loading" }: { color?: string; label?: string }) {
return (
<>
<style>{css}</style>
<span className="pd" role="status" style={{ ["--pd-color" as string]: color }}>
<i /><i /><i />
<span className="pd__sr">{label}</span>
</span>
</>
);
}
export default PulseDots;
Install
npx shadcn@latest add https://ownlyplans.com/r/bhaskar/pulse-dots-loader.json
Adds the React files to components/ownlyplans/ in a project set up with shadcn and Tailwind CSS. Or copy them from the Code tab.
About
Pure CSS with staggered delays. It carries role=”status” and a hidden label so screen readers hear “Loading”.