Stripe.com Inspired Dropdown Mega Menu With JavaScript

Category: Javascript , Menu & Navigation | December 30, 2020
Authornaveen-27
Last UpdateDecember 30, 2020
LicenseMIT
Views4,612 views
Stripe.com Inspired Dropdown Mega Menu With JavaScript

An animated dropdown mega menu that animates menu items when switching between nav links. Inspired by Stripe.com’s header navigation.

How to use it:

1. Code the HTML for the Dropdown Mega Menu.

<header>
  <img src="./images/logo.svg" alt="Stripe Logo" />
  <nav class="navbar">
    <ul class="nav__links">
      <li data-expand="products" class="nav--link">Products</li>
      <li data-expand="use-cases" class="nav--link">Use Cases</li>
    </ul>
  </nav>
  <div class="tip"></div>
  <section class="header__expandMenu">
    <div class="menu__container">
      <div id="products">
        <div class="sub__menu">
          <h3 class="title">PAYMENTS</h3>
          <ul class="subMenu__items">
            <li class="subMenu--item">
              <img src="./images/payment.svg" alt="" />
              <span class="label__container">
                <div class="label">
                  Payments
                  <img
                    class="right--arrow"
                    src="./images/right-arrow.svg"
                    alt=""
                  />
                </div>
                <div class="label--desc">Online payments</div>
              </span>
            </li>
            <li class="subMenu--item">
              <img src="./images/terminal.svg" alt="" />
              <span class="label__container">
                <div class="label">
                  Terminal
                  <img
                    class="right--arrow"
                    src="./images/right-arrow.svg"
                    alt=""
                  />
                </div>
                <div class="label--desc">In-person payments</div>
              </span>
            </li>
            <li class="subMenu--item">
              <img src="./images/connect.svg" alt="" />
              <span class="label__container">
                <div class="label">
                  Connect
                  <img
                    class="right--arrow"
                    src="./images/right-arrow.svg"
                    alt=""
                  />
                </div>
                <div class="label--desc">Payments for platforms</div>
              </span>
            </li>
            <li class="subMenu--item">
              <img src="./images/billing.svg" alt="" />
              <span class="label__container">
                <div class="label">
                  Billing
                  <img
                    class="right--arrow"
                    src="./images/right-arrow.svg"
                    alt=""
                  />
                </div>
                <div class="label--desc">Subscriptions & invoicing</div>
              </span>
            </li>
          </ul>
        </div>
        <div class="sub__menu">
          <h3 class="title">PAYOUTS</h3>
          <ul class="subMenu__items">
            <li class="subMenu--item">
              <img src="./images/payouts.svg" alt="" />
              <span class="label__container">
                <div class="label">
                  Payouts
                  <img
                    class="right--arrow"
                    src="./images/right-arrow.svg"
                    alt=""
                  />
                </div>
                <div class="label--desc">Programmatic payouts</div>
              </span>
            </li>
            <li class="subMenu--item">
              <img src="./images/issuing.svg" alt="" />
              <span class="label__container">
                <div class="label">
                  Issuing
                  <img
                    class="right--arrow"
                    src="./images/right-arrow.svg"
                    alt=""
                  />
                </div>
                <div class="label--desc">Card creation</div>
              </span>
            </li>
          </ul>
        </div>
        <div class="sub__menu">
          <h3 class="title">BUISNESS OPERATIONS</h3>
          <ul class="subMenu__items">
            <li class="subMenu--item">
              <img src="./images/radar.svg" alt="" />
              <span class="label__container">
                <div class="label">
                  Radar
                  <img
                    class="right--arrow"
                    src="./images/right-arrow.svg"
                    alt=""
                  />
                </div>
                <div class="label--desc">Fraud & risk management</div>
              </span>
            </li>
            <li class="subMenu--item">
              <img src="./images/sigma.svg" alt="" />
              <span class="label__container">
                <div class="label">
                  Sigma
                  <img
                    class="right--arrow"
                    src="./images/right-arrow.svg"
                    alt=""
                  />
                </div>
                <div class="label--desc">Custom reports</div>
              </span>
            </li>
            <li class="subMenu--item">
              <img src="./images/atlas.svg" alt="" />
              <span class="label__container">
                <div class="label">
                  Atlas
                  <img
                    class="right--arrow"
                    src="./images/right-arrow.svg"
                    alt=""
                  />
                </div>
                <div class="label--desc">Start-up incorporation</div>
              </span>
            </li>
          </ul>
        </div>
      </div>
      <div id="use-cases">
        <ul class="subMenu__items">
          <li class="subMenu--item">
            <img class="icon--production" src="./images/saas.svg" alt="" />
            <span class="label__container">
              <div class="label">
                SaaS
                <img
                  class="right--arrow"
                  src="./images/right-arrow.svg"
                  alt=""
                />
              </div>
              <div class="label--desc">
                Manage recurring bills and subscriptions
              </div>
            </span>
          </li>
          <li class="subMenu--item">
            <img
              class="icon--production"
              src="./images/marketplace.svg"
              alt=""
            />
            <span class="label__container">
              <div class="label">
                Marketplaces
                <img
                  class="right--arrow"
                  src="./images/right-arrow.svg"
                  alt=""
                />
              </div>
              <div class="label--desc">
                Pay out globally and facilitate multi-party payments
              </div>
            </span>
          </li>
          <li class="subMenu--item">
            <img
              class="icon--production"
              src="./images/platform.svg"
              alt=""
            />
            <span class="label__container">
              <div class="label">
                Platform
                <img
                  class="right--arrow"
                  src="./images/right-arrow.svg"
                  alt=""
                />
              </div>
              <div class="label--desc">
                Let customers accept payments within your platform
              </div>
            </span>
          </li>
        </ul>
      </div>
    </div>
  </section>
</header>

2. The required CSS styles.

header {
  display: flex;
  padding: 1.5rem 3rem;
  justify-content: space-around;
  align-items: center;
}
.nav__links {
  display: flex;
  list-style: none;
  color: #fff;
  font-weight: 700;
}
.nav--link {
  padding: 0 1rem;
  transition: opacity 100ms linear;
  cursor: pointer;
}
.btn {
  padding: 0.5rem 1rem;
  display: flex;
  align-items: center;
  font-family: inherit;
  font-weight: 700;
  color: #fff;
  outline: none;
  border: none;
  background-color: #ffffff35;
  border-radius: 2rem;
  transition: background-color 100ms linear;
  cursor: pointer;
}
.arrow {
  width: 20px;
  height: 10px;
  position: relative;
  transform: translateX(-4px);
}
.line {
  position: absolute;
  top: 46%;
  right: 0;
  height: 2px;
  width: 7px;
  background-color: #fff;
  transform-origin: 100% 50%;
}
.arrow--sideUp {
  transform: rotate(45deg);
}
.arrow--sideDown {
  transform: rotate(-45deg);
}
.arrow--hoverLine {
  width: 12px;
  transform: scale(0);
}
.arrow,
.line {
  transition: transform 100ms ease-in;
}
.btn--primary:hover {
  background-color: #ffffff65;
}
.btn:hover .arrow {
  transform: none;
}
.btn:hover .arrow--hoverLine {
  transform: scale(1);
}
.tip {
  width: 1.25rem;
  height: 1.25rem;
  background-color: #fff;
  position: absolute;
  top: 4.15rem;
  left: 0;
  clip-path: polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%);
  transition: transform 100ms linear;
  opacity: 0;
}
.header__expandMenu {
  position: absolute;
  top: 4.5rem;
  left: 50%;
  width: 95%;
  height: 90%;
  transform-origin: 0%;
  transform: translateX(-50%) rotate3d(1, 0, 0, -15deg);
  background-color: white;
  border-radius: 0.5rem;
  perspective: 100px;
  transition: width 250ms ease, height 250ms ease, opacity 150ms ease,
    transform 200ms ease-in;
  overflow: hidden;
  opacity: 0;
  pointer-events: none;
}
.menu__container {
  width: 100%;
  height: 100%;
  background-color: white;
}
.menu__container > * {
  position: absolute;
  top: 0;
  left: 50%;
  padding: 2rem;
  overflow: hidden;
  transform: translateX(-35%);
  transition: transform 250ms linear, opacity 250ms ease;
  opacity: 0;
}
#products {
  display: grid;
  grid-template-columns: repeat(3, 300px);
}
.item--one {
  grid-column: span 2;
}
#use-cases {
  width: 450px;
}
.subMenu__items {
  list-style: none;
}
.title {
  font-size: 0.85rem;
  margin-bottom: 1.75rem;
}
.subMenu--item {
  display: flex;
  align-items: center;
  cursor: pointer;
}
.label__container {
  margin-left: 0.75rem;
}
.label {
  font-size: 0.9rem;
  font-weight: 700;
  color: rgba(0, 0, 73, 0.644);
}
.label--desc {
  font-size: 0.9rem;
  color: rgb(83, 83, 83);
  transform: translateY(-3px);
  transition: color 100ms ease;
}
.subMenu--item + .subMenu--item {
  margin-top: 1.5rem;
}
.icon--production {
  transform: translateY(-55%) scale(1.1);
}
.right--arrow {
  width: 12px;
  transform: translateY(1px) scale(0, 1);
  transition: transform 150ms ease-in-out;
}
.subMenu--item:hover .right--arrow {
  transform: translateY(1.75px) scale(1);
}
.subMenu--item:hover .label--desc {
  color: black;
}
.active {
  z-index: 1;
  opacity: 1;
  transform: translatex(-50%);
}
.prev {
  transform: translateX(-65%);
}
.expand {
  opacity: 1;
  pointer-events: all;
  transform: translateX(-50%) rotateX(0);
}
.hover {
  opacity: 0.5;
}
.new--expand {
  transition: opacity 150ms ease, transform 150ms ease-in;
}
.first {
  transition: none;
}

3. The main JavaScript to enable the dropdown mega menu.

const handleMouseEnter = (e) => {
  if (!e.target.dataset.expand) {
    return;
  }
  navsVisited += 1;
  if (navsVisited === 1) {
    expandMenu.classList.add("new--expand");
    menus.forEach((menu) => menu.classList.add("first"));
    indicator.classList.add("first");
  } else {
    expandMenu.classList.remove("new--expand");
    menus.forEach((menu) => menu.classList.remove("first"));
    indicator.classList.remove("first");
  }
  navLinks.forEach((navLink) => {
    if (navLink === e.target) {
      navLink.classList.add("hover");
      currentNav = navLink;
    } else {
      navLink.classList.remove("hover");
    }
  });
  const navLinkCenter = Math.floor(
    e.target.offsetLeft + e.target.clientWidth / 2
  );
  indicator.style.transform = `translateX(${navLinkCenter}px)`;
  indicator.style.opacity = "1";
  const targetMenu = document.querySelector(`#${e.target.dataset.expand}`);
  const targetCoords = targetMenu.getBoundingClientRect();
  const { width: targetWidth, height: targetHeight } = targetCoords;
  expandMenu.style.width = targetWidth + "px";
  expandMenu.style.height = targetHeight + "px";
  const prevMenu = targetMenu.previousElementSibling;
  targetMenu.classList.remove("prev");
  if (prevMenu) {
    prevMenu.classList.add("prev");
  }
  menus.forEach((menu) => {
    if (menu.id === targetMenu.id) {
      menu.classList.add("active");
    } else {
      menu.classList.remove("active");
    }
  });
  expandMenu.classList.add("expand");
};
const handleMouseLeave = (e) => {
  if (isMouseOnMenu || e.y > 50) {
    return;
  }
  forceInitialState();
};
const forceInitialState = () => {
  expandMenu.classList.remove("expand", "active");
  currentNav.classList.remove("hover");
  menus.forEach((menu) => menu.removeAttribute("class"));
  indicator.style.opacity = "0";
  currentNav = null;
  navsVisited = 0;
};
const expandMenu = document.querySelector(".header__expandMenu");
const menus = expandMenu.querySelectorAll(".menu__container > *");
const navLinks = document.querySelectorAll(".nav--link");
const indicator = document.querySelector(".tip");
let isMouseOnMenu = false;
let currentNav;
let navsVisited = 0;
const {
  height: menuHeight,
  width: menuWidth,
} = expandMenu.getBoundingClientRect();
navLinks.forEach((navLink) => {
  navLink.addEventListener("mouseenter", handleMouseEnter);
});
expandMenu.addEventListener("mouseenter", () => {
  if (expandMenu.style.opacity === "1") {
    isMouseOnMenu = true;
  }
});
expandMenu.addEventListener("mouseleave", (e) => {
  if (e.y > 70) {
    isMouseOnMenu = false;
    forceInitialState();
  }
});
document
  .querySelector(".nav__links")
  .addEventListener("mouseleave", handleMouseLeave);

You Might Be Interested In:


Leave a Reply