Loader Snippets — Free HTML CSS JS Loading Indicators
26 loader components · Skeleton, Progress Ring, Dots, Progress Bar, Countdown Timer, Loading Overlay, Upload Progress, Number Slot, Breathing · Exports to React, Vue, Angular & Tailwind
What's included
Features
About this tool
Loader Snippets — Free Skeleton Shimmer, SVG Progress Ring, Number Slot Machine & Breathing Animation
Loading indicators and progress animations solve a fundamental UX problem: users cannot tell whether a slow interface is broken or simply loading. Showing the right loading state — a content placeholder, a percentage progress arc, a countdown reveal, or a focus breathing prompt — reduces perceived wait time significantly and prevents abandonment. This collection covers four technically distinct loading and progress patterns.
Every snippet uses pure CSS animations or minimal JavaScript. No animation library, no canvas framework, no dependency.
Skeleton Loader shows the layout of upcoming content before the data arrives. The shimmer effect uses a linear-gradient with background-size: 200% — the gradient is twice the element width. A CSS keyframe shifts background-position from 200% to -200%, sweeping the light highlight across the skeleton. Because background-position changes are handled by the GPU compositor and do not trigger layout or paint, this animation runs at 60fps on low-end devices. This is the same technique used by Facebook, LinkedIn, and Slack.
SVG Progress Ring draws a circular progress arc using stroke-dashoffset. The mathematics: CIRCUMFERENCE = 2 × π × radius. Setting stroke-dasharray: CIRCUMFERENCE makes the entire circle one dash. Setting stroke-dashoffset: CIRCUMFERENCE × (1 - percentage/100) offsets that dash so only the percentage portion is visible. transform: rotate(-90deg) on the circle element rotates the arc start from the default 3 o'clock position to 12 o'clock. Animating stroke-dashoffset from CIRCUMFERENCE to the target value creates the fill-in effect.
Number Slot Machine scrolls digit columns via translateY. Each column contains 0–9 stacked vertically. Scrolling to digit 7 means translating the column to show position 7. overflow: hidden on the container clips the non-visible digits. The animation uses CSS transition: transform with a cubic-bezier for the authentic slot deceleration effect.
Breathing Animation cycles through inhale, hold, and exhale phases with a smooth CSS scale animation. The circle grows during inhale and shrinks during exhale. A phase countdown timer shows the remaining seconds for the current phase (e.g. 4 seconds inhale, 7 seconds hold, 8 seconds exhale for the 4-7-8 pattern). The CSS animation-duration is set in JavaScript to match each phase duration exactly. Three evidence-based breathing pattern presets are included: box breathing (4-4-4-4), the 4-7-8 relaxation technique, and equal breathing (5-5).
Real-world uses
Common Use Cases
Got questions?
Frequently Asked Questions
The shimmer uses background: linear-gradient(90deg, #e2e8f0 25%, #f1f5f9 50%, #e2e8f0 75%) with background-size: 200% on each skeleton element. This makes the gradient twice the element width. A CSS keyframe animates background-position from 200% 0 to -200% 0, sweeping the lighter highlight from right to left across the element. Because background-position is handled entirely by the GPU compositor — it does not trigger layout recalculation or paint — it runs at 60fps without impacting main thread performance.
CIRCUMFERENCE = 2 × Math.PI × radius — the total pixel length of the circle perimeter. stroke-dasharray: CIRCUMFERENCE sets the entire perimeter as one continuous dash. stroke-dashoffset moves where that dash starts along the perimeter. Setting dashoffset to CIRCUMFERENCE × (1 - pct/100) hides the last (1-pct/100) portion of the dash, making only pct% of the ring visible. Animating dashoffset from CIRCUMFERENCE (empty ring) to the target value creates the fill animation. rotate(-90deg) on the circle rotates the arc start from the default 3 o'clock to 12 o'clock.
Keep the skeleton container and the real content container as siblings with the content container hidden initially: content.style.display = "none". When your fetch or async call resolves successfully: skeleton.remove() and content.style.display = "block". In React: use a boolean isLoading state — render {isLoading ? <SkeletonCard /> : <RealCard data={data} />}. You can also fade the transition by animating opacity on the content container.
Click "JSX" on each snippet to download a React component. For the skeleton loader, the shimmer animation is pure CSS and works unchanged in JSX — just ensure the CSS is imported. For the progress ring, pass pct as a prop and compute the strokeDashoffset value as CIRCUMFERENCE * (1 - pct / 100) inside the component. Use a useEffect with a transition delay to animate from 0 to the target pct on mount for an entry animation.