JSFiddle - React, Tailwind, and code Playground

by Yunus Gaziev

HTML

<div class="loader">
    <svg class="circular-loader"viewBox="0 0 120 120" >
      <circle class="loader-path" cx="60" cy="60" r="55" fill="none" stroke="#70c542" stroke-width="10" />
    </svg>
</div>
<p>
  <button id="start" type="button">start</button> <button id="success" type="button">success</button>
</p>
<div class="checkmark"></div>

SCSS

.loader {
  width: 120px;
  height: 120px;
}
.circular-loader {
  width: 120px;
  height: 120px;
}
.loader-path {
  stroke-dasharray: 345;
  stroke-dashoffset: 0;
  stroke-linecap: round;
}

.loader.is-loading {
  animation-name: rotate;
  animation-duration: 2.2s;
  animation-timing-function: linear;
  animation-fill-mode: forwards;
}
.is-loading .loader-path {
  animation-name: dash;
  animation-duration: 2s;
  animation-timing-function: ease-in-out;
  animation-fill-mode: forwards;
}
.loader.is-waiting,
.is-waiting .loader-path {
  animation-iteration-count: infinite;
}
.loader.is-done,
.is-done .loader-path {
  animation-iteration-count: 1;
}

@keyframes dash {
  0% {
    stroke-dasharray: 0, 345;
  }
  50% {
    stroke-dasharray: 120, 345;
  }
  100% {
    stroke-dasharray: 345, 345;
    stroke-dashoffset: -345;
  }
}

@keyframes rotate {
  100% {
    transform: rotate(360deg);
  }
}

.checkmark {
  position: relative;
  width: 74px;
  height: 38px;
  transform: rotate(-45deg);
  
  &::before,
  &::after {
    content: '';
    position: absolute;
    border-radius: 10px;
    background-color: #000;
    transition: width 100ms linear, height 100ms linear;
  }
   
  &::before {
    top: 0;
    left: 0;
    width: 10px;
    height: 0;
  }

  &::after {
   left: 0;
   bottom: 0;
   width: 0;
   height: 10px;
   transition-delay: 100ms;
  }
  
  &.is-complete {
    &::before {
      height: 100%;
    }
    &:after {
      width: 100%;
    }
  }
}

JavaScript

let checkmark = document.querySelector('.checkmark');

let loader = document.querySelector('.loader');

let start = document.getElementById('start');
let success = document.getElementById('success');

start.addEventListener('click', () => {
	loader.classList.add('is-loading', 'is-waiting');
});

success.addEventListener('click', () => {
	loader.classList.remove('is-waiting');
  loader.classList.add('is-done');
});

setTimeout(() => {
	checkmark.classList.add('is-complete');
}, 100);