<div id="root"></div>
* {
  box-sizing: border-box;
}

body {
  background: #ffddee;
  margin: 0;
  height: 100vh;
}

.menu {
  display: inline-flex;
  flex-direction: column;
  height: 4rem;
}

.menu ul {
  margin: 0;
  padding: 0 1rem;
  list-style: none;
  display: flex;
  flex-direction: column;
  font-family: sans-serif;
  font-size: 2rem;
  text-transform: uppercase;
  font-weight: bold;
  overflow: hidden;
  gap: 1rem;
  color: #444;
}

.burger {
  border: 0;
  background: transparent;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  padding: 1rem;
  cursor: pointer;
}

.burger span {
  display: block;
  width: 2rem;
  height: 0.3rem;
  background-color: #444;
}
import React, { useState } from "https://esm.sh/react";
import ReactDOM from "https://esm.sh/react-dom";
import { motion } from "https://esm.sh/framer-motion";

function App() {
  const [isActive, setIsActive] = useState(false);

  return (
    <motion.div
      className="menu"
      initial="closed"
      animate={isActive ? "open" : "closed"}
      variants={{
        open: { backgroundColor: "#fff", height: "100vh" }
      }}
    >
      <motion.button className="burger" onClick={() => setIsActive(!isActive)}>
        <motion.span variants={{ open: { rotate: 45, y: "0.8rem" } }} />
        <motion.span variants={{ open: { opacity: 0 } }} />
        <motion.span variants={{ open: { rotate: -45, y: "-0.8rem" } }} />
      </motion.button>

      <motion.ul
        variants={{
          open: { transition: { staggerChildren: 0.2, delayChildren: 0.2 } }
        }}
      >
        {["Home", "About", "Contact"].map((page) => (
          <motion.li
            variants={{ closed: { opacity: 0 }, open: { opacity: 1 } }}
          >
            {page}
          </motion.li>
        ))}
      </motion.ul>
    </motion.div>
  );
}

ReactDOM.render(<App />, document.getElementById("root"));
View Compiled

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.