webdevpuneet.com

Loading Overlay — Free HTML CSS JS Snippet

Loading Overlay · Loaders · Plain HTML, CSS & JS · Live preview

CategoryLoaders

Copy & paste

Source Code

<div class="page">
  <div class="content-card">
    <h2>Dashboard Overview</h2>
    <p>This card represents your page content.</p>
    <div class="mini-grid">
      <div class="stat-block"><div class="stat-n">$48,295</div><div class="stat-l">Revenue</div></div>
      <div class="stat-block"><div class="stat-n">1,284</div><div class="stat-l">Users</div></div>
      <div class="stat-block"><div class="stat-n">94.2%</div><div class="stat-l">Uptime</div></div>
    </div>
  </div>

  <div class="trigger-row">
    <button class="trigger-btn" onclick="showOverlay('spinner')">Spinner overlay</button>
    <button class="trigger-btn" onclick="showOverlay('dots')">Dots overlay</button>
    <button class="trigger-btn" onclick="showOverlay('progress')">Progress overlay</button>
    <button class="trigger-btn outline" onclick="hideOverlay()">Hide</button>
  </div>

  <!-- Overlay -->
  <div class="overlay" id="overlay">
    <div class="overlay-box" id="overlay-box">
      <!-- Spinner -->
      <div class="loader-wrap" id="l-spinner">
        <div class="spinner"></div>
        <div class="overlay-msg">Loading data…</div>
      </div>
      <!-- Dots -->
      <div class="loader-wrap hidden" id="l-dots">
        <div class="dots"><span></span><span></span><span></span></div>
        <div class="overlay-msg">Processing…</div>
      </div>
      <!-- Progress -->
      <div class="loader-wrap hidden" id="l-progress">
        <div class="overlay-msg">Uploading files…</div>
        <div class="prog-track"><div class="prog-fill" id="prog-fill"></div></div>
        <div class="prog-pct" id="prog-pct">0%</div>
      </div>
    </div>
  </div>
</div>

Extend with AI

Take This Snippet Further With AI

The AI prompt for this one is for Patreon supporters ($3 a month), along with a site with no ads. Supporters enter the passcode once and it is remembered in this browser.

· Become a supporter

What's included

Features

Overlay: position:absolute inset:0, opacity fade, pointer-events:none toggle
backdrop-filter: blur(6px) — frosted glass effect over the covered content
Spinner variant: border-top-color accent, linear rotation keyframe
Dots variant: 3 bouncing dots with staggered translateY animation
Progress variant: random-increment simulation, auto-close at 100%
Three variants share one overlay container — hidden via .hidden class
hideOverlay() shared function clears intervals and removes .visible class
For full-page overlay: change position:absolute to position:fixed

About this UI Snippet

Loading Overlay — Spinner, Dots & Progress Bar Variants with Blur Backdrop and Opacity Fade

Screenshot of the Loading Overlay snippet rendered live

A loading overlay blocks a section or full page during an asynchronous operation — API call, file upload, data processing — to prevent user interaction with partially loaded content and communicate that something is happening. This snippet provides three overlay variants: a classic CSS spinner, bouncing dots, and a simulated progress bar — all with a frosted glass backdrop-filter blur and opacity fade transition.

The overlay backdrop

The overlay uses position: absolute; inset: 0 to cover the parent container entirely. background: rgba(255,255,255,0.85) provides a semi-transparent white tint. backdrop-filter: blur(6px) blurs the content behind the overlay — the frosted glass effect. In the closed state, opacity: 0 and pointer-events: none make the overlay invisible and non-interactive. Adding .visible switches to opacity: 1 and pointer-events: all. The CSS transition: opacity 0.25s fades smoothly.

Spinner variant

The spinner uses border-top-color: #6366f1 on an otherwise light grey bordered circle, rotated continuously via a CSS keyframe animation. The cubic-bezier timing is linear for a consistent revolution speed.

Dots variant

Three bouncing dots use translateY(-10px) at the 50% keyframe with staggered animation-delay (0s, 0.2s, 0.4s). Opacity fades from 0.4 to 1 in sync.

Progress bar variant

A simulated setInterval advances the progress bar by a random amount (2–10%) every 300ms. When it reaches 100%, the interval clears and hideOverlay() fires after a 600ms delay. In production, replace the simulation with a real upload progress event: xhr.upload.onprogress = e => { const pct = e.loaded/e.total*100; updateProgress(pct); }.

Positioning: absolute vs fixed

The overlay uses position: absolute to cover only the parent .page container. For a full-page overlay, change to position: fixed; inset: 0; z-index: 9999 and attach it to the document body instead of a container div. The blur and opacity behaviour is identical — only the covered area changes.

Performance note

backdrop-filter: blur() is GPU-composited but can be expensive on older mobile devices. If performance is a concern, replace backdrop-filter with background: rgba(255,255,255,0.94) without blur. Test with Chrome DevTools Performance to confirm the overlay renders without triggering main-thread layout recalculation. All three loader animations (spinner rotation, dots bounce, progress bar fill) use transform and width — both GPU-safe properties that avoid layout recalculation on each animation frame. For mobile-first projects, always prefer transform-based animations over properties that trigger layout or paint — this principle applies equally to the overlay's loader variants and any other CSS animation throughout the codebase.

Step by step

How to Use

  1. 1
    Click any trigger button to see the overlay variantSpinner overlay shows for 3 seconds then auto-hides. Dots overlay shows for 3 seconds then auto-hides. Progress overlay simulates a file upload, advancing the bar and auto-closing at 100%.
  2. 2
    Wrap your content in a position:relative containerThe overlay covers the nearest position:relative ancestor. Ensure your .page or section container has position: relative set. The overlay uses position: absolute; inset: 0 to fill it exactly.
  3. 3
    Wire to a real API call or upload eventShow on fetch start: showOverlay("spinner"). Hide on .then() or .finally(): hideOverlay(). For uploads: show progress variant, then wire xhr.upload.onprogress to updateProgress(pct). Hide on upload complete.
  4. 4
    Convert to a full-page overlayChange position: absolute to position: fixed on .overlay. Remove border-radius: 16px. The overlay now covers the entire viewport instead of just the parent container.
  5. 5
    Change the overlay opacity and blurUpdate rgba(255,255,255,0.85) to control the backdrop tint opacity. Increase or decrease blur(6px) on backdrop-filter. For dark-themed pages, use rgba(0,0,0,0.6) for a dark overlay with white spinner.
  6. 6
    Export in your formatClick "HTML" for a standalone file, "JSX" for a React component with visible/type state managed by useState, or "Tailwind" for a Tailwind CSS version.

Real-world uses

Common Use Cases

API call and data fetch loading states
Show the spinner overlay when initiating a fetch call and hide it in .finally() — this covers the content area regardless of whether the request succeeds or fails, preventing partial state display.
File upload and form submission feedback
Show the progress bar variant during file uploads, or the dedicated upload progress card for per-file detail. Wire xhr.upload.onprogress to the progress fill width. The visual bar gives users confidence the upload is proceeding and shows completion percentage without requiring them to leave the page.
Dashboard and widget loading states
Overlay individual dashboard cards while their data loads. Use the spinner variant for short waits (under 2 seconds) and the dots variant for unknown-duration processing. Each widget has its own overlay, so sections load independently as their APIs respond.
Route transitions in single-page applications
For SPA route changes, show a full-page overlay (position:fixed) while new page data loads. The blur and fade create a premium transition feel. Remove the overlay when the new page content is ready to render.
Study backdrop-filter blur and opacity toggle patterns
The overlay demonstrates how backdrop-filter: blur() creates the frosted glass effect over real content. The opacity + pointer-events toggle pattern is reusable for any show/hide transition — the pattern prevents invisible elements from blocking clicks.
Image and media processing feedback screens
Show the progress bar variant while processing images (resize, convert, compress) or media files (transcode, merge, compress). Update progress from your processing API's progress webhook or polling endpoint.
Related: Diagonal Shimmer Skeleton
See the Diagonal Shimmer Skeleton for a related loaders pattern worth pairing with this one.

Got questions?

Frequently Asked Questions

Replace the setInterval simulation with an XMLHttpRequest upload progress listener: const xhr = new XMLHttpRequest(); xhr.upload.onprogress = e => { if (e.lengthComputable) { const pct = Math.round(e.loaded/e.total*100); document.getElementById("prog-fill").style.width = pct + "%"; document.getElementById("prog-pct").textContent = pct + "%"; if (pct >= 100) setTimeout(hideOverlay, 600); } }; xhr.open("POST", "/upload"); xhr.send(formData). Show the progress overlay before calling xhr.send().

Move the .overlay div to be a direct child of body (not inside the .page container). Change position: absolute to position: fixed in the CSS and remove border-radius: 16px. Now the overlay covers the full viewport. Set z-index: 9999 to ensure it appears above all page content. The opacity fade and blur work identically — only the covered area changes.

Change background: rgba(255,255,255,0.85) to background: rgba(0,0,0,0.6) on .overlay. Change .overlay-msg color to #f1f5f9. Change .spinner border colour to rgba(255,255,255,0.15) and border-top-color to #fff. The dots and progress bar can remain the same since they use the accent colour which reads on dark.

Manage loading state with useState: const [loading, setLoading] = useState({ visible: false, type: "spinner" }). Render the overlay: {loading.visible && <div className="overlay visible">...</div>}. On API call: setLoading({visible:true, type:"spinner"}) before fetch, setLoading({visible:false, type:"spinner"}) in finally(). Pass the loading type to conditionally render the correct variant inside the overlay box.