JSFiddle - React, Tailwind, and code Playground

by Lazaro Contreras

HTML

<div id="menu">
  <svg>
    <path fill="white">
      <animate attributeName="d" dur="0.15s"/>
    </path>
  </svg>
</div>

CSS

* {
  margin: 0;
}

html,
body {
  background: #333639;
}

div#menu {
  display: inline-block;
  width: 300px;
  height: 100vh;
  background: transparent;
  transform: translateX(-250px);
  position: relative;
  transition: all 0.15s linear;
}

div#menu.active {
  transform: none;
}

div#menu svg {
  width: 100%;
  height: 100%;
  overflow: unset;
}

JavaScript

var w = menu.offsetWidth,
  h = menu.offsetHeight,
  open = false,
  anioff = false

var svg = menu.querySelector("svg");
svg.setAttribute("viewbox", "0 0 " + w + " " + h);

var ani = menu.querySelector("svg path animate");
var box = menu.querySelector("svg path");
box.setAttribute("d", "M 0 0 L0 " + h + " L" + w + " " + h + " Q " + w + " " + (h / 2) + " " + w + " 0 Z");

menu.addEventListener("touchstart", () => {
  window.addEventListener("touchmove", move);
})

window.addEventListener("touchend", () => {
  terAni("touchmove");
  if (anioff) {
    menu.classList.toggle("active");
    open = !open
    anioff = !anioff
  }
})

menu.addEventListener("mousedown", () => {
  window.addEventListener("mousemove", move);
})

window.addEventListener("mouseup", () => {
  terAni("mousemove");
  if (anioff) {
    menu.classList.toggle("active");
    open = !open
    anioff = !anioff
  }
})

function terAni(s) {
  window.removeEventListener(s, move);
  box.setAttribute("d", "M 0 0 L0 " + h + " L" + w + " " + h + " Q " + w + " " + (h / 2) + " " + w + " 0 Z");
  ani.beginElement();
  ani.setAttribute("to", "M 0 0 L0 " + h + " L" + w + " " + h + " Q " + w + " " + (h / 2) + " " + w + " 0 Z");
  setTimeout(() => {
    ani.setAttribute("from", "M 0 0 L0 " + h + " L" + w + " " + h + " Q " + w + " " + (h / 2) + " " + w + " 0 Z");
  }, 150);
}

function move(e) {
  let x = e.clientX,
    y = e.clientY;
  if (open) {
    if (x < w && x > w * 0.5) {
      anioff = false
      box.setAttribute("d", "M 0 0 L0 " + h + " L" + w + " " + h + " Q " + x + " " + y + " " + w + " 0 Z");
      ani.setAttribute("from", "M 0 0 L0 " + h + " L" + w + " " + h + " Q " + x + " " + y + " " + w + " 0 Z");
    } else if (x < w) {
      box.setAttribute("d", "M 0 0 L0 " + h + " L" + w + " " + h + " Q " + w * 0.5 + " " + y + " " + w + " 0 Z");
      ani.setAttribute("from", "M 0 0 L0 " + h + " L" + w + " " + h + " Q " + w * 0.5 + " " + y + " " + w + " 0 Z");
      anioff = true
    }
  } else {
    x += 250
 ...