JSFiddle - React, Tailwind, and code Playground

by caub

HTML

<button id="butt">
Test butt
</button>

CSS

* {box-sizing: border-box;}

button > span {
  border-radius: 50%;
  position: absolute;
  width: calc(2px*var(--ripple-radius));
  height: calc(2px*var(--ripple-radius));
  display: inline-block;
  opacity: 0.66;
  -webkit-user-select: none;
  user-select: none;
  pointer-events: none;
}

button {
  height: 2em;
  font-size: 1.5em;
  margin: 1em;
  border-radius: 2px;
  border: none;
  outline: none;
  transition: all .2s ease-in-out;
  overflow: hidden;
  white-space: nowrap;
  position:relative;
  cursor: pointer;
  -webkit-user-select: none;
  user-select: none;
}
button {
  box-shadow: 0 4px 6px rgba(7,7,7, 0.19),
    0 3px 3px rgba(7,7,7, 0.23);
}
button:active {
  box-shadow: 0 0px 1px rgba(7,7,7, 0.19),
    0 1px 1px rgba(7,7,7, 0.23);
}

JavaScript

var duration = 1000, radius = 100;

document.body.style.setProperty('--ripple-radius', radius);

const ripple = e=>{
	const {left, top} = e.currentTarget.getBoundingClientRect();
	var d = e.currentTarget.appendChild(document.createElement('span'));
  
	//console.log(e.clientX-left, e.clientY-top-50)
  Object.assign(d.style, {
  	left:e.clientX-left-radius+'px',
    top:e.clientY-top-radius+'px',
    backgroundColor: `hsla(${10*Math.random()+200}, 30%, 70%, .7)`
  });
  d.animate([
    {transform: 'scale(0)'},
    {transform: 'scale(1)'},
  ], {
    duration: duration,
    easing: 'cubic-bezier(.22,.67,.52,.92)',
    fill: 'forwards',
  });
  const up = e=>{
    document.removeEventListener('mouseup', up);
    const opacity = d.animate([
      {opacity: 0.66},
      {opacity: 0},
    ], {
      duration,
      fill: 'forwards',
    });
    opacity.onfinish = ()=> {
      d.remove();
    };
  }
  document.addEventListener('mouseup', up);
}

butt.onmousedown = e=>{
  ripple(e);
}