<div class="container">
  <a href="#" class="ripple-effect">Ripple Effect</a>
</div>
body {
  font-family: Roboto, sans-serif;
  background-color: #fafafa;
}

.container {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 90vh;
}

.ripple-effect {
  text-decoration: none;
  font-weight: 500;
  position: relative;
  font-size: 14px;
  color: #333;
  background-color: #ddd;
  display: block;
  padding: 14px 20px;
  border-radius: 10px;
  overflow: hidden;
  div {
    position: absolute;
    transform: translate(-50%, -50%);
    pointer-events: none;
    border-radius: 50rem;
    background-color: red;
    animation: rippleEffect 1s linear infinite;
  }
}

@keyframes rippleEffect {
  from {
    width: 0;
    height: 0;
    opacity: .5;
  }
  to {
    width: 500px;
    height: 500px;
    opacity: 0;
  }
}
View Compiled
const buttons: HTMLElement = document.querySelectorAll('.ripple-effect')

buttons.forEach((button: HTMLElement) => {
  button.addEventListener('click', (e: Event) => {
    
    const ANIMATION_SPEED: number = 1000
    
    let x: number = e.clientX - e.target.offsetLeft
    let y: number = e.clientY - e.target.offsetTop
    
    const ripple: HTMLElement = document.createElement('div')
    
    ripple.style.left = x + 'px'
    ripple.style.top = y + 'px'
    button.appendChild(ripple)
    
    setTimeout(() => {
      ripple.remove()
    }, ANIMATION_SPEED)
  })
})
View Compiled

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.