CSS Loader Gallery — 8 Pure CSS Spinners & Loaders Snippet

CSS Loader Gallery · Animations · Plain HTML, CSS & JS · Live preview

Share & Support

What's included

Features

8 distinct pure-CSS loaders: spinner, dots, pulse ring, skeleton, orbit, progress bar, grid fade, typing
Every animation runs on @keyframes — no JavaScript, no requestAnimationFrame
Per-loader copy: clicking copies that loader's minified CSS only
Live previews in a responsive grid — see exactly what you will get
Light-mode CSS in each loader string (dark gallery is the container only)
Shimmer skeleton using background-position sweep technique
Staggered animation-delay on nth-child for wave/cascade effects
Toast confirmation with iframe-safe copy fallback

About this UI Snippet

CSS Loader Gallery — Spinner, Skeleton, Dots, Pulse, Orbit & More

Screenshot of the CSS Loader Gallery snippet rendered live

CSS loaders and spinners are among the most-searched UI components for front-end developers — every app needs at least one loading indicator, and searching for the right style accounts for significant traffic to developer resource sites. This snippet provides a gallery of eight distinct, pure-CSS loaders: a classic spinner, bouncing dots, a pulse ring, skeleton bars, an orbit, a progress bar, a 3×3 grid fade, and typing dots. Each is a live preview; clicking copies the minified CSS ready to paste.

Pure CSS — no JavaScript for the animations

Every loader uses only CSS @keyframes and animation properties — no JavaScript runs the animations. JavaScript is used only for the gallery rendering and copy functionality. This is the entire point of a "pure CSS loader": it works even in JavaScript-disabled contexts, it does not block the main thread, and it has no runtime overhead beyond the initial paint.

The eight loader types

The spinner (border-top-color with border-radius: 50% and rotate) is the most common loader pattern, appropriate for almost any context. Bouncing dots (three circles with staggered animation-delay on a scale and opacity keyframe — see the standalone dots loader) signal activity without directionality. The pulse ring (expanding, fading border-radius: 50%) is common for social and chat apps. Skeleton bars (shimmer gradient on placeholder lines) prevent layout shift and set content expectations during fetch. The orbit (two pseudo-elements: a rotating outer ring and a static inner dot) has a physics feel. The progress bar (translateX indeterminate sweep) communicates a linear task without a known percentage. The 3×3 grid fade (staggered opacity on nine cells) has a data-grid or terminal aesthetic. Typing dots (bouncing dots on a vertical path) are the standard chat "is typing" indicator.

The copy-per-loader model

Each loader's CSS is stored as a minified string in the loaders array alongside its HTML. Clicking a card copies only that loader's CSS, not the entire gallery stylesheet. The CSS in each string uses light-mode neutrals (rather than the dark gallery background) so it works on any page. The copy uses the Clipboard API with an execCommand fallback and shows a toast confirmation.

The shimmer skeleton technique

The skeleton loader uses a background: linear-gradient(90deg, light, lighter, light) at 200% width, animated with background-position from 200% to -200% — this makes the shimmer sweep from right to left across the bars. The key is background-size: 200% 100% so the gradient is wider than the element; the animation sweeps it through. This technique is the standard approach used by Facebook, LinkedIn, and most modern content feeds.

Animation-delay staggering

The bouncing dots, grid fade, and typing dots all use animation-delay on nth-child elements to offset a shared animation, creating a wave or cascade effect from a single @keyframes definition. This is a core CSS animation technique: one animation, multiple delays, complex visual result.

Build with AI

Build, Understand, Optimize, and Extend It With AI

You don't have to reverse-engineer why each loader's CSS is stored twice (once for the gallery, once minified in the loaders array) to see the design decision behind it. Paste this snippet's HTML, CSS, and JS into an AI coding assistant like Claude and ask it to explain exactly why the gallery's own dark-theme CSS is kept separate from the light-mode CSS string that actually gets copied to the clipboard, and how the shimmer skeleton's background-size and background-position values work together to sweep a highlight across a bar. The same assistant can help optimize it — for instance asking whether generating nine staggered animation-delay rules by hand for the grid-fade loader could instead be computed with a CSS custom property and nth-child arithmetic to cut down repetition. It's also useful for extending the gallery: ask it to add a dark-mode variant of each copyable CSS string as a toggle, let users tweak the accent color live and see it reflected in the copied output, or add a ninth loader based on a completely different CSS technique like clip-path or mask. Treat the code less like a finished artifact and more like a starting point for a conversation.

Prompt to recreate it

Copy this into your AI assistant of choice to build the effect from scratch, or as a jumping-off point for your own variant:

text
Build a gallery of at least eight distinct pure-CSS loading animations in plain HTML, CSS, and JavaScript, where clicking any loader copies its standalone CSS to the clipboard — no animation library.

Requirements:
- Every individual loader's motion must come entirely from CSS keyframes and the animation property — JavaScript must never drive any loader's visual animation directly, only the gallery rendering and the copy interaction.
- Represent each loader as a data object containing a name, an HTML markup string, and a separate, portable CSS string using light-neutral colors (independent of the gallery's own dark background), so the copied CSS works correctly if pasted into any other page regardless of that page's theme.
- Render the gallery by iterating that array of loader objects to build one card per loader dynamically, rather than hand-writing a separate markup block per loader.
- Include at least these distinct animation techniques across the set of loaders: a rotating border spinner, staggered scale/opacity bouncing dots, an expanding-and-fading ring, a shimmering skeleton placeholder using an animated background-position sweep on an oversized gradient, a two-part orbiting ring with a static center, an indeterminate sliding progress bar, a staggered-opacity grid of cells, and a bouncing "is typing" dot indicator.
- Clicking a loader card must copy only that loader's own CSS string (not the whole gallery's stylesheet) using the async clipboard API, with a synchronous execCommand-based fallback for contexts where that API is unavailable, and show a temporary toast confirmation that automatically hides itself after a couple of seconds.
- Any loader using staggered timing (bouncing dots, grid cells, typing indicator) must implement the stagger via animation-delay on individual child elements sharing one keyframe definition, not by defining a separate keyframe per element.

Want to tighten it up first? Run this prompt through the AI Prompt Studio to score it across 8 quality dimensions, catch anti-patterns, and tune the wording for Claude, ChatGPT, or Gemini before you paste it in.

Step by step

How to Use

  1. 1
    Browse the loadersAll eight loaders animate live on page load. No JavaScript runs the animations — they are pure CSS @keyframes.
  2. 2
    Click to copy a loaderClick any loader card to copy its minified CSS to the clipboard. A "CSS copied!" toast confirms the action.
  3. 3
    Paste into your projectPaste the copied CSS into your stylesheet or a <style> tag. Add the corresponding HTML structure (one or two elements) to your page.
  4. 4
    Change the accent colourFind #6366f1 (indigo) in the copied CSS and replace it with your brand colour. Most loaders use only one or two colour values.
  5. 5
    Adjust the sizeScale a loader by changing its width and height values proportionally. Animations based on border-width or gap may also need tuning at very different sizes.
  6. 6
    Export for your frameworkClick "React" for a gallery component rendering each loader from the array. Click "Vue" for a Vue 3 SFC with the same pattern.

Real-world uses

Common Use Cases

Choose and embed a loader for any async state
Use the spinner for button loading states, the skeleton for content placeholders during data fetch, the progress bar for file uploads, and the typing dots for chat interfaces. The gallery lets you compare all eight live and pick the right one for the context before copying.
Design system loading indicator library
Add all eight loaders to your design system under a "Loading" category. Standardise on two or three for your product (a spinner for actions, a skeleton for content, dots for chat) and document when to use each. Export them as design tokens with the brand colour substituted.
Skeleton loading for card and list components
The skeleton loader is specifically designed for content-placeholder patterns: show matching skeleton bars while the API fetches, then swap them for the real content. The shimmer animation keeps the UI feeling responsive and prevents the jarring flash of an empty layout.
Study CSS animation fundamentals
The eight loaders together cover the core CSS animation toolkit: rotate transforms (spinner, orbit), scale/opacity keyframes (dots, pulse ring), background-position sweep (shimmer), translateX (progress bar), staggered animation-delay (grid fade, typing dots), and pseudo-element animation. Each is a study in what is possible with @keyframes alone.
Chat interface "is typing" indicator
The typing dots loader is the direct implementation of the three-dot "is typing" bubble used in every chat UI from iMessage to Slack. Drop it into your WebSocket-based chat to show when another user is composing a message, using WebSocket events to add and remove the loader element.
Embed in a UI component picker or no-code tool
Add the gallery as a loader picker in a no-code builder or CMS — users click a preview to select that loader style for their page, and the builder injects the HTML and CSS automatically. The per-loader copy model maps directly to this pattern.

Got questions?

Frequently Asked Questions

The skeleton bar has background: linear-gradient(90deg, light-colour 25%, lighter-colour 50%, light-colour 75%) with background-size: 200% 100% so the gradient is twice as wide as the element. The keyframe animates background-position from 200% 0 to -200% 0, sweeping the lighter midpoint of the gradient across the bar from right to left. The 200% size and the -200% end position together ensure the shimmer fully enters from the right and fully exits to the left with a smooth transition.

Find all occurrences of #6366f1 (indigo) in the copied CSS string and replace with your primary brand colour. For loaders with a lighter secondary colour (#a5b4fc), replace with a lighter tint of your brand colour (increasing the L value in HSL by 15–25%). For loaders with a border colour (#e2e8f0 or #1e2744), replace with the appropriate neutral for your light or dark theme.

A spinner is a generic "activity in progress" indicator that blocks the full content area with no structural information. A skeleton loader mimics the shape of the incoming content (lines for text, rectangles for images) so users can predict the layout before it loads. Skeletons dramatically reduce perceived load time and layout shift, making them the preferred choice for content-heavy lists, cards, and dashboards where the structure is known. Use a spinner for undetermined-length operations like form submissions where no content shape is expected.

Push a new object to the loaders array: { name: "My Loader", html: "<div class=\"my-loader\"></div>", css: ".my-loader{...}@keyframes my-anim{...}" }. Add the corresponding CSS to the gallery stylesheet for the live preview to render. call render() (or trigger a re-render in React/Vue state). The card is automatically added to the grid at the next render.

Accept a loaders array as a prop (or hardcode it as a constant). Map over it to render one card per loader, using dangerouslySetInnerHTML for the loader markup or rebuilding it as JSX. The copy handler reads the loader's css string and calls navigator.clipboard.writeText, then sets a copiedIndex in useState to show the toast. Because the animations are pure CSS, there is no animation state to manage in React — the keyframes run entirely in the browser. For the Tailwind version, click "Tailwind" to get the same markup with utility classes instead of a scoped stylesheet.