JSFiddle - React, Tailwind, and code Playground

HTML

<!DOCTYPE html> 
<html lang="en">
	<head>
		<meta charset="utf-8">
		<title>Power switch</title>
	</head>
	<body> 

		<a id="myButton">
      <svg  xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="90" height="90" viewbox="0 0 540 540">
	      <defs>
		      <style type="text/css">

			      .off {stroke: var(--off);}

			      .power {
				      stroke: var(--on);
				      stroke-dasharray: 1000;
				      animation: powering 3s linear 0s 1 normal forwards;
			      }
			      @keyframes powering {
				      0% {stroke-dashoffset: 1000;}
				      100% {stroke-dashoffset: 0;}
			      }
            
            .shutdown {
				      stroke: var(--on);
				      stroke-dasharray: 1000;
				      animation: shutdowning var(--time) linear 0s 1 normal forwards;
			      }
			      @keyframes shutdowning {
				      0% {stroke-dashoffset: var(--offset);}
				      100% {stroke-dashoffset: 1000;}
			      }

		      </style>
	      </defs>

	      <path fill="none" stroke="var(--off)" stroke-width="78" stroke-linecap="round" d="M400,143 a200,200 0 1,1 -260,0" />
	      <g>
		      <path class="off" id="myIcon1" stroke-width="80" stroke-linecap="round" fill="none" d="M400,143 a200,200 0 1,1 -260,0" />
		      <line class="off" id="myIcon2" stroke-width="80" stroke-linecap="round" x1="270" y1="240" x2="270" y2="45" />
	      </g>
      </svg>
		</a>
    <div class="off2" id="animationTrick"></div>
	</body>
</html>

CSS

:root {
	--bg: #405480;
	--off: #2C303A;
	--on: #114B8E;
  --time: 3s;
  --offset: 1000;
}

html, body {
	background: var(--bg);
	color: #f5f5f5;
	height: 100%;
	display: flex;
	flex-direction: column;
	justify-content: center;
	align-items: center;
}

a {
	display: block;
	cursor: pointer;
	text-decoration: none;
	user-select: none;
	-webkit-user-select: none;
	padding: 35px 120px;
	line-height: 1;
	white-space: nowrap;
	color: #fff;
	border-radius: 12px;
	border: 1px solid #00397C;
	box-shadow: 0 3px 2px rgba(0, 0, 0, 0.24),
				0 9px 4px rgba(22, 21, 21, 0.45),
				15px 15px 10px rgba(22, 21, 21, 0.2),
				inset 0 -3px 6px rgba(0, 0, 0, 0.3),
				inset 0 2px 0 rgba(255, 255, 255, 0.27),
				inset 0 4px 6px #405480,
				inset 1px 2px 3px 0px rgba(0, 0, 0, 0);
}
a:hover:not(.lock) {
	box-shadow: 0 3px 2px rgba(0, 0, 0, 0.24),
				0 0 0 rgba(22, 21, 21, 0),
				5px 5px 10px rgba(22, 21, 21, 0.2),
				inset 0 -3px 6px rgba(0, 0, 0, 0.3),
				inset 0 2px 1px rgba(255, 255, 255, 0.2),
				inset 0px 4px 6px 0px #405480,
				inset 1px 2px 3px 0px rgba(0, 0, 0, 0);
}
a:active:not(.lock) {
	box-shadow: 0 1px 1px 0 rgba(255, 255, 255, 0.32),
				1px 1px 10px rgba(22, 21, 21, 0.2),
				5px 5px 10px rgba(22, 21, 21, 0),
				inset 0 3px 6px rgba(0, 0, 0, 0.3),
				inset 6px 6px 10px rgba(0, 0, 0, 0.3),
				inset 0 -2px 6px rgba(255, 255, 255, 0.1),
				inset 1px 2px 3px 0px rgba(0, 0, 0, 0.5);
}
.lock {
	cursor: not-allowed;
	box-shadow: 0 1px 1px 0 rgba(255, 255, 255, 0.32),
				1px 1px 10px rgba(22, 21, 21, 0.2),
				5px 5px 10px rgba(22, 21, 21, 0),
				inset 0 3px 6px rgba(0, 0, 0, 0.3),
				inset 6px 6px 10px rgba(0, 0, 0, 0.3),
				inset 0 -2px 6px rgba(255, 255, 255, 0.1),
				inset 1px 2px 3px 0px rgba(0, 0, 0, 0.5);
}
div#animationTrick {
  position: absolute;
  visibility: hidden;
  overflow: hidden;
  height: 0px;
}
.power2 {
  width: 1000px;
  animation: powering2 3s linear 0s 1 normal forwards;
}
@keyframes powering2 {
  0% { width: 1000px; }
  100% { width:...

JavaScript

/*
L'icone on-off est constituée d'un arc de cercle (symbole 'off' nommé myIcon1) et d'un trait (symbole 'on' nommé myIcon2)
La classe de ces symboles SVG est définie comme suit :

       myIcon1  myIcon2  myButton
       --------------------------
         off      off               état initial
        power     off               appui sur le bouton
        power    blink   disabled   appui sur le bouton de plus de 3 secondes
         on       on     disabled   après wake-on-LAN et ping réussi (en test: après 10 secondes)
         off      off               après extinction et ping en échec (en test : 1 minute)
*/
var wolTimeout, pingTimeout, suspendTimeout; 

['mousedown', 'touchstart', 'keypress'].forEach(e => {
	document.getElementById('myButton').addEventListener(e, ev => {
		if((e != 'keypress' || (e == 'keypress' && ev.which == 32)) && document.getElementById('myIcon1').classList.contains('off')) {
    	let el1 = document.getElementById('myIcon1');
      let el2 = document.getElementById('animationTrick');
			el1.classList.replace('off', 'power');
      el2.classList.replace('off2', 'power2');
		}
	})
});

['mouseup', 'touchend', 'keyup'].forEach(e => {
	document.getElementById('myButton').addEventListener(e, ev => {
		if((e != 'keyup' || (e == 'keyup' && ev.which == 32)) && document.getElementById('myIcon1').classList.contains('power') && document.getElementById('myIcon2').classList.contains('off')) {
			let el1 = document.getElementById('myIcon1');
      let el2 = document.getElementById('animationTrick');
      el1.style.animationPlayState = 'paused';
      el2.style.animationPlayState = 'paused';
      let offset = el2.clientWidth;
      document.documentElement.style.setProperty('--offset', offset);
      let time = 3 * (1000 - offset) / 1000;
      document.documentElement.style.setProperty('--time', time + 's');
      el1.style.animationPlayState = 'running';
      el2.style.animationPlayState = 'running';
      el1.classList.replace('power',...