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);