Click-to-Reveal Blur

December 20, 2025

🤓 Want a quick “privacy blur” effect? Wrap any section with data-reveal and it will render blurred until clicked/tapped. Clicking toggles reveal/hide, and you can also use a tiny “Reveal all / Hide all” control if you want.

<!--
Click-to-Reveal Blur (Privacy Toggle)
- No frameworks
- Works on desktop + mobile
- Blur any block by adding: data-reveal
- Optional per-block label: data-reveal-label="Tap to reveal"

Usage examples:
  <div data-reveal data-reveal-label="Tap to reveal preview"> ... </div>
  <img data-reveal src="thumb.jpg" alt="Preview">

Optional controls:
  <button type="button" data-reveal-all>Reveal all</button>
  <button type="button" data-hide-all>Hide all</button>
-->

<style>
/* Scoped with .vs-reveal-root so it won’t mess with your site */
.vs-reveal-root [data-reveal]{
  position:relative;
  cursor:pointer;
  user-select:none;
  -webkit-tap-highlight-color: transparent;
}

/* The blurred state */
.vs-reveal-root [data-reveal].is-hidden{
  filter: blur(14px);
  transform: translateZ(0); /* keeps blur smooth on some browsers */
}

/* Overlay label */
.vs-reveal-root [data-reveal].is-hidden::after{
  content: attr(data-reveal-label);
  position:absolute;
  inset:0;
  display:grid;
  place-items:center;
  text-align:center;
  padding:14px;
  font: 800 14px/1.2 system-ui,-apple-system,Segoe UI,Roboto,Arial,sans-serif;
  color:#0c0f14;
  background: rgba(255,255,255,.72);
  border: 1px solid rgba(30,40,80,.14);
  border-radius: 14px;
  box-shadow: 0 10px 30px rgba(20,24,70,.08);
  pointer-events:none;
}

/* Make overlay fit nicely when the reveal element is a block with no radius */
.vs-reveal-root [data-reveal].is-hidden{
  border-radius: 14px;
  overflow: hidden;
}

/* Optional: a subtle “pressed” feel */
.vs-reveal-root [data-reveal]:active{
  transform: scale(.995);
}
</style>

<script>
(function(){
  "use strict";

  // Wrap your reveal section in <div class="vs-reveal-root"> ... </div>
  // If you don’t, we’ll fall back to document (still safe because selectors are scoped).
  var root = document.querySelector(".vs-reveal-root") || document;

  function ensureLabel(el){
    if (!el.getAttribute("data-reveal-label")) {
      el.setAttribute("data-reveal-label", "Tap to reveal");
    }
  }

  function hide(el){
    ensureLabel(el);
    el.classList.add("is-hidden");
    el.setAttribute("aria-hidden", "true");
  }

  function show(el){
    el.classList.remove("is-hidden");
    el.removeAttribute("aria-hidden");
  }

  function toggle(el){
    if (el.classList.contains("is-hidden")) show(el);
    else hide(el);
  }

  function all(){
    return Array.prototype.slice.call(root.querySelectorAll("[data-reveal]"));
  }

  // Initialize all reveal blocks as hidden by default
  all().forEach(function(el){
    hide(el);
    // Make sure positioned overlay works on inline elements too
    var cs = window.getComputedStyle(el);
    if (cs.display === "inline") el.style.display = "inline-block";
    // If element has no height (e.g., empty), overlay can't show; that's fine.
  });

  // Click/tap to toggle (supports nested clicks too)
  root.addEventListener("click", function(e){
    var el = e.target.closest ? e.target.closest("[data-reveal]") : null;
    if (!el || !root.contains(el)) return;
    toggle(el);
  }, true);

  // Optional controls
  var btnRevealAll = root.querySelector("[data-reveal-all]");
  if (btnRevealAll) {
    btnRevealAll.addEventListener("click", function(){
      all().forEach(show);
    });
  }

  var btnHideAll = root.querySelector("[data-hide-all]");
  if (btnHideAll) {
    btnHideAll.addEventListener("click", function(){
      all().forEach(hide);
    });
  }
})();
</script>

<!-- Example wrapper (optional, but recommended for scoping) -->
<div class="vs-reveal-root">

  <p style="margin:10px 0">
    <button type="button" data-reveal-all>Reveal all</button>
    <button type="button" data-hide-all>Hide all</button>
  </p>

  <div data-reveal data-reveal-label="Tap to reveal preview" style="padding:14px;border:1px solid rgba(30,40,80,.14);border-radius:14px;background:#fff">
    <strong>Hidden preview</strong><br>
    This block starts blurred and reveals on click/tap.
  </div>

</div>

Comments (0)

No comments yet — be the first.

← Back to all scripts