JSFiddle - React, Tailwind, and code Playground

by RAX7

HTML

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 100 100">
  <defs>
    <mask id="blur-mask"></mask>
    <filter id="blur-filter">
      <feGaussianBlur in="SourceGraphic" stdDeviation="2"/>
      <feComponentTransfer>
        <feFuncA type="discrete" tableValues="1 1"/>
      </feComponentTransfer>
    </filter>
  </defs>

  <image
    xlink:href="https://images.unsplash.com/photo-1484244233201-29892afe6a2c?ixlib=rb-1.2.1&auto=format&fit=crop&w=750&q=80"
    preserveAspectRatio="xMidYMid slice"
    height="100%" width="100%"/>
  
  <image
    xlink:href="https://images.unsplash.com/photo-1484244233201-29892afe6a2c?ixlib=rb-1.2.1&auto=format&fit=crop&w=750&q=80"
    preserveAspectRatio="xMidYMid slice"
    height="100%" width="100%"
    filter="url(#blur-filter)"
    mask="url(#blur-mask)"/>
</svg>

JavaScript

function genMask(w, h) {
	const NS = 'http://www.w3.org/2000/svg';
	const els = [];
  
  for (let wi = 0; wi < w; wi++) {
    for (let hi = 0; hi < h; hi++) {
    	const rect = document.createElementNS(NS, 'rect');
      rect.setAttribute('x', wi * (100 / w) + '%');
      rect.setAttribute('y', hi * (100 / h) + '%');
      rect.setAttribute('width', (100 / w) + '%');
      rect.setAttribute('height', (100 / h) + '%');
      rect.setAttribute('fill', '#fff');
      rect.setAttribute('stroke', '#fff');
      rect.setAttribute('stroke-width', '1');
      els.push(rect);
    }
  }
  
  return els;
}

const mask = document.querySelector('#blur-mask');
const maskParts = genMask(20, 20);

maskParts.forEach(part => mask.appendChild(part));
maskParts.sort(() => Math.random() - 0.5);

let partIndex = 0;
function unblur() {
	maskParts[partIndex].setAttribute('fill', '#000');
  maskParts[partIndex].setAttribute('stroke', '#000');
  partIndex++;
  if (partIndex < maskParts.length) {
    setTimeout(unblur, 100);
  }
}

unblur();