Stripe.com Inspired Dropdown Mega Menu With JavaScript

Category: Javascript , Menu & Navigation | December 30, 2020
Author: naveen-27
Views Total: 425 views
Official Page: Go to website
Last Update: December 30, 2020
License: MIT

Preview:

Stripe.com Inspired Dropdown Mega Menu With JavaScript

Description:

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