<div class="wrapper">
  <img src="https://uploads-ssl.webflow.com/649c7f9a7739b1da3f52cb29/650ca0f162b5c62b83930c15_Zenyth Assessment_Logo-01.svg" width="200px" alt="Zenyth logo">
  <h1>Accessible Mega Menu Pattern</h1>

  
  <header class="znt-mega-menu-container">
      <nav class="znt-mega-menu" aria-label="Main Navigation">
        <a href="#" class="znt-mega-menu-logo" aria-label="Zenyth Logo">
            <img src="https://uploads-ssl.webflow.com/649c7f9a7739b1da3f52cb29/650ca0f162b5c62b83930c15_Zenyth Assessment_Logo-01.svg" width="200px" alt="Zenyth logo">
        </a>
        <button class="znt-mobile-menu-item" znt-disclosure_toggle-button hidden>
          <span class="visually-hidden">
            Menu
          </span>
        </button>
        <ul class="znt-nav-list" znt-disclosure_toggle-panel znt-disclosure_focusout>
          <li class="znt-nav-item has-link" znt-disclosure_focusout znt-disclosure_hoverable>
            <a href="https://www.zenythgroup.com/">Link + Button</a>
            <button class="znt-mega-menu-item" znt-disclosure_toggle-button>
              <span class="visually-hidden">
                Toggle submenu
              </span>
            </button>
            <div class="znt-mega-menu-panel" znt-disclosure_toggle-panel>
              <div class="znt-mega-menu-panel-container">
                <div class="znt-grid">
                  <div class="znt-col-4-12">
                    <h2 id="znt-mega-menu-links_01">
                      Content - Sub-items - 01
                    </h2>
                    <ul aria-labelledby="znt-mega-menu-links_01" class="znt-mega-menu-links">
                      <li><a href="#grape">Grape</a></li>
                      <li><a href="#honeydew">Honeydew</a></li>
                      <li><a href="#kiwi">Kiwi</a></li>
                      <li><a href="#lemon">Lemon</a></li>
                      <li><a href="#mango">Mango</a></li>
                    </ul>
                  </div>
                  <div class="znt-col-4-12">
                    <div class="znt-card">
                      <img src="https://assets.website-files.com/64a6dd1a72b0c8b654f1d0be/64ada3cdf387aa442a47dc66_pexels-cottonbro-studio-5054354.jpg" alt="" class="znt-card-image">
                      <div class="znt-card-body">
                        <h2 class="znt-card-heading">
                          <a href="#">
                            Strengthening Digital Accessibility
                          </a>
                        </h2>
                        <p class="znt-card-copy">
                          Navigating digital accessibility compliance can be daunting. ZenythGroup helps decode complexities, ensuring your digital space is inclusive for all.
                        </p>
                      </div>
                    </div>
                  </div>
                  <div class="znt-col-4-12">
                    <div class="znt-card">
                      <img src="https://assets.website-files.com/64a6dd1a72b0c8b654f1d0be/64ada3cdf387aa442a47dc66_pexels-cottonbro-studio-5054354.jpg" alt="" class="znt-card-image">
                      <div class="znt-card-body">
                        <h2 class="znt-card-heading">
                          <a href="#">
                            Strengthening Digital Accessibility
                          </a>
                        </h2>
                        <p class="znt-card-copy">
                          Navigating digital accessibility compliance can be daunting. ZenythGroup helps decode complexities, ensuring your digital space is inclusive for all.
                        </p>
                      </div>
                    </div>
                  </div>
                </div>
              </div>
            </div>
          </li>
          <li class="znt-nav-item">
            <button class="znt-mega-menu-item" znt-disclosure_toggle-button>
              Button Item
            </button>
            <div class="znt-mega-menu-panel" znt-disclosure_toggle-panel>
              <div class="znt-mega-menu-panel-container">
                <div class="znt-grid">
                  <div class="znt-col-4-12">
                    <h2 id="znt-mega-menu-links_02">
                      Content - Sub-items - 02
                    </h2>
                    <ul aria-labelledby="znt-mega-menu-links_02" class="znt-mega-menu-links">
                      <li><a href="#raspberry">Raspberry</a></li>
                      <li><a href="#strawberry">Strawberry</a></li>
                      <li><a href="#tangerine">Tangerine</a></li>
                      <li><a href="#uglifruit">Ugli Fruit</a></li>
                      <li><a href="#vanilla">Vanilla</a></li>
                      <li><a href="#watermelon">Watermelon</a></li>
                    </ul>
                  </div>
                  <div class="znt-col-4-12">
                    <div class="znt-card">
                      <img src="https://assets.website-files.com/64a6dd1a72b0c8b654f1d0be/64ada3cdf387aa442a47dc66_pexels-cottonbro-studio-5054354.jpg" alt="" class="znt-card-image">
                      <div class="znt-card-body">
                        <h2 class="znt-card-heading">
                          <a href="#">
                            Strengthening Digital Accessibility
                          </a>
                        </h2>
                        <p class="znt-card-copy">
                          Navigating digital accessibility compliance can be daunting. ZenythGroup helps decode complexities, ensuring your digital space is inclusive for all.
                        </p>
                      </div>
                    </div>
                  </div>
                  <div class="znt-col-4-12">
                    <div class="znt-card">
                      <img src="https://assets.website-files.com/64a6dd1a72b0c8b654f1d0be/64ada3cdf387aa442a47dc66_pexels-cottonbro-studio-5054354.jpg" alt="" class="znt-card-image">
                      <div class="znt-card-body">
                        <h2 class="znt-card-heading">
                          <a href="#">
                            Strengthening Digital Accessibility
                          </a>
                        </h2>
                        <p class="znt-card-copy">
                          Navigating digital accessibility compliance can be daunting. ZenythGroup helps decode complexities, ensuring your digital space is inclusive for all.
                        </p>
                      </div>
                    </div>
                  </div>
                </div>
              </div>
            </div>
          </li>
        </ul>
      </nav>
    </header>
  
  <br><hr><br>
  <p>For more information you can reach a friendly accessibility expert at <a href="https://zenythgroup.com/contact" target="_blank">Zenyth</a></p>
</div>
/* Default Codepen Styles */
* {
  font-family: ui-serif, Assistant;
}
.wrapper {
  margin: 0 auto 2.5em;
  max-width: 660px;
  padding-top: 100px;
}
h1 {
  padding-bottom: 25px;
}
#info {
  margin-top: 60px;
}





/* Mega menu styles */

/* Mega menu variables */
:root {
  --navigation-height: 60px;
  --navigation-bar-background: #fff;
  --navigation-panel-background: #fff;
  --mega-menu-width: 1280px;

  --megamenu-breakpoint: 1050px;
}


/* Zenyth Toggle button - Basic CSS */
.znt-mega-menu-item[znt-disclosure_toggle-button]:not([aria-expanded="true"]) + [znt-disclosure_toggle-panel] {
  display: none; }

.znt-mega-menu-logo {
  display: inline-block;
  width: 150px;
  height: 50px; }

.znt-mega-menu-logo img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  object-position: center; }

.znt-nav-list {
  padding: 0;
  margin: 0;
  list-style: none;
  display: flex;
  align-items: center; }



.znt-mega-menu {
  max-width: var(--mega-menu-width);
  margin: 0 auto;
  display: flex;
  justify-content: space-between;
  align-items: center;
  height: var(--navigation-height); }
  .znt-mega-menu-container {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    z-index: 999;
    height: var(--navigation-height);
    background-color: var(--navigation-bar-background);
    border-bottom: 1ppx solid #f9f9f9;
    box-shadow: 3px 3px 6px rgba(0,0,0,.3); }

.znt-mega-menu-panel {
  position: fixed;
  top: var(--navigation-height);
  left: 0;
  width: 100%;
  min-height: 400px;
  z-index: 999;
  background-color: var(--navigation-panel-background);
  overflow: auto;
  box-shadow: 4px 4px 8px rgba(0,0,0,.3); }


.znt-mega-menu-panel-container {
  max-width: var(--mega-menu-width);
  margin: 0 auto;
  padding: 32px 64px; }

.znt-nav-item {
  border-top: 3px solid transparent;
  border-bottom: 3px solid transparent;
  transition: .5s;
  cursor: pointer; }

.znt-nav-item:hover,
.znt-nav-item:has([aria-expanded="true"]) {
  border-bottom-color: #53389e; }

.znt-mega-menu-item {
  position: relative;
  padding: 8px 40px 8px 14px;
  background-color: transparent;
  border: none;
  font-family: system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Noto Sans,Ubuntu,Cantarell,Helvetica Neue,Oxygen,Fira Sans,Droid Sans,sans-serif;
  font-weight: 600;
  font-size: 16px;
  cursor: pointer; }


.znt-nav-item.has-link { position: relative; }

.znt-nav-item.has-link:after {
  content: "";
  width: 100%;
  height: 20px;
  position: absolute;
  bottom: -20px;
  left: 0; }

.znt-nav-item.has-link > a {
  color: #000;
  text-decoration: none;
  display: inline-block;
  padding: 8px 40px 8px 8px;
  font-size: 16px;
  width: 100%; 
  font-family: system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Noto Sans,Ubuntu,Cantarell,Helvetica Neue,Oxygen,Fira Sans,Droid Sans,sans-serif;
  font-weight: 600; }

.znt-nav-item.has-link .znt-mega-menu-item {
  position: absolute;
  top: 0;
  right: 0;
  width: 32px;
  height: 32px;
  padding: 2px;
  border: 1px solid transparent;
  font-size: 16px;
  font-family: system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Noto Sans,Ubuntu,Cantarell,Helvetica Neue,Oxygen,Fira Sans,Droid Sans,sans-serif;
  font-weight: 600; }

.znt-nav-item.has-link .znt-mega-menu-item:after { right: 5px; }

/* .znt-nav-item.has-link .znt-mega-menu-item:hover {
  border-color: #53389e;
} */

.znt-mega-menu-item:after {
  content: "";
  position: absolute;
  top: 50%;
  right: 8px;
  transform: translateY(-50%);
  width: 20px;
  height: 20px;
  background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAMAAABg3Am1AAAAe1BMVEUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC9eBywAAAAKHRSTlMA+/Lm9yreViHr4bGBa0Q9I9fSondPHgbGl5BxZWBKODMvJxkU2qmIvhibKwAAAOBJREFUSMftk9kSgjAMRZGl7Mgii7sCav//C4UhNWgkjjP6xnnL7Umn06bazMxPcZKq5Y22SpyRL6RMGs5vUim9WFW1ITuEM+0Xl94wLChFX+EOlNgbDAG1P5SwA8UyQPAhKFWHe+b98pFlEOlH6p9cWLx2Pu2IXv2lDkvZc76B2Iwm/DUEtCMfpweT+ooVLC1szHLl3zSEduxVYi8gCrS3hBIIh3qn/C11iUH6CeQM9IR8R4B3wIH3iLfMgi+F7/hNh877OG3MLDLzjNP+kdqg/4nHEfTH8hRpWmgzM3/lDuZHLpdqYoKIAAAAAElFTkSuQmCC);
  background-size: 16px;
  background-repeat: no-repeat;
  background-position: center; }

[aria-expanded="true"].znt-mega-menu-item:after { transform: rotateX(180deg) translateY(50%); }

.znt-mega-menu a:focus,
.znt-mega-menu a:focus-visible,
.znt-mega-menu button:focus,
.znt-mega-menu button:focus-visible { outline: auto !important; }

.znt-mega-menu-links {
  padding: 0;
  margin: 0;
  list-style: none; }

.znt-mega-menu-links a {
  display: block;
  padding: 6px 14px;
  width: 100%;
  text-decoration: none;
  font-size: 16px;
  color: black;
  font-family: ui-serif, Assistant;
  border-bottom: 3px solid transparent;
  transition: .25s; }
.znt-mega-menu-links a:hover { border-color: #53389e; }

@media(min-width: 600px) {

  .znt-split-2-cols {
    column-count: 2;
    column-gap: 20px;
    -moz-column-count: 2;
    -moz-column-gap: 20px;
    -webkit-column-count: 2;
    -webkit-column-gap: 20px; }

  .znt-split-3-cols {
    column-count: 3;
    column-gap: 20px;
    -moz-column-count: 3;
    -moz-column-gap: 20px;
    -webkit-column-count: 3;
    -webkit-column-gap: 20px; } }




/* Mobile menu */
.znt-mobile-menu-item {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  right: 16px;
  width: 44px;
  height: 44px;
	background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAQAAAD9CzEMAAAAPUlEQVR42u3UsQkAIBADwAzo/hPoHIq1rSLKXfoPfJEE+ElJS9+UlrIW1G3nZ+qFguMvAmyRLQJbZIuA1w0vh9NQsAZ9IwAAAABJRU5ErkJggg==);
  background-size: 20px;
  background-position: center;
  background-repeat: no-repeat;
  background-color: transparent;
  border: 1px solid #53389e; }

@media(max-width: 1050px){
  .znt-mobile-menu-item[znt-disclosure_toggle-button]:not([aria-expanded="true"]) + [znt-disclosure_toggle-panel] { display: none; }
  .znt-mobile-menu-item { display: block; }

  .znt-nav-list {
    position: fixed;
    top: var(--navigation-height);
    width: 100%;
    height: calc(100% - var(--navigation-height));
    display: block;
    overflow: hidden;
    background-color: var(--navigation-panel-background);
    padding: 16px;
  }

  .znt-nav-list li,
  .znt-mega-menu-item {
    width: 100%;
    text-align: left;
    font-size: 16px;
    width: 100%; 
    font-family: system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Noto Sans,Ubuntu,Cantarell,Helvetica Neue,Oxygen,Fira Sans,Droid Sans,sans-serif;
    font-weight: 600; 
  }

  .znt-nav-item.has-link .znt-mega-menu-item {
  position: absolute;
  top: 0;
  right: 0;
  width: 32px;
  height: 32px;
  padding: 2px;
  border: 1px solid transparent;
  font-size: 16px;
  font-family: system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Noto Sans,Ubuntu,Cantarell,Helvetica Neue,Oxygen,Fira Sans,Droid Sans,sans-serif;
  font-weight: 600; }

  .znt-mega-menu-panel {
    position: relative;
    top: 0;
    padding: 0 32px 32px 32px;
    border: 1px solid #f9f9f9;
    height: calc(100vh - var(--navigation-height));
  }

  .znt-mega-menu-panel-container {
    padding: 0;
  }
}



.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  opacity: 0;
}

* {
  box-sizing: border-box;
}


/* Zenyth Card component */
.znt-card {
  position: relative;
  width: 100%;
  border: 1px solid #ececec;
  box-shadow: 3px 3px 6px rgba(0,0,0,.3);
  transition: .5s;
}

.znt-card:hover {
  box-shadow: 6px 6px 10px rgba(0,0,0,.5);
}

.znt-card-image {
  height: 180px;
  width: 100%;
  object-fit: cover;
  object-position: center;
}

.znt-card-body {
  padding: 16px;
}

.znt-card-heading {
  font-size: 18px;
  font-weight: 600;
  line-height: 1.2;
  margin: 0;
}

.znt-card .znt-card-heading a {
  outline: none !important;
}

.znt-card-heading a:after {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
}


.znt-card:focus-within {
  outline: auto;
  outline-offset: 4px;
}

.znt-card-copy {
  font-size: 16px;
}



/* Zenyth Grid syztem */
.znt-grid {
  display: flex;
  margin: -8px;
  flex-wrap: wrap;
}

[class*="znt-col"] {
  flex-shrink: 0;
}

.znt-col-8-12 {
  width: 66.6666%;
  padding: 8px;
}

.znt-col-4-12 {
  width: 33.3333%;
  padding: 8px;
}

@media(max-width: 1050px) {

  .znt-grid {
    flex-direction: column;
  }

  [class*="znt-col"] {
    width: 100%;
  }
}
// Global button toggle
$(document).ready(function () {
  if ($("[znt-disclosure_toggle-button]").length) {

    // Base aria-expanded toggler
    $("[znt-disclosure_toggle-button]").each(function () {
      $(this).off('click').click(function () {
        const expanded = $(this).attr("aria-expanded") === "true";
        if (expanded) {
          $(this).attr("aria-expanded", false);
        } else {
          $(this).attr("aria-expanded", true);
          // Sends focus to the first item within the [znt-disclosure_toggle-panel], for disclosure search components 
          const $togglePanel = $(this).siblings("[znt-disclosure_toggle-panel][znt-disclosure_focus-first]");
          // Delay focus by second to give the SR time to announce the state
          setTimeout(function () {
            $togglePanel
              .find("a[href], button, textarea, input, select, [tabindex='0']")
              .first()
              .focus();
          }, 100);
        }
      });
    });
    // END OF - Base aria-expanded toggler


    // ESC Key implementation
    // Closes the panel pressing ESC key
    $(document).keyup(function (e) {
      if (e.key === "Escape") {
        $("[znt-disclosure_toggle-button]").each(function () {
          $(this).siblings('[znt-disclosure_toggle-panel]').find(':focus').closest('[znt-disclosure_toggle-panel]').siblings('[znt-disclosure_toggle-button]').focus();
          $(this).attr("aria-expanded", false);
        });
      }
    });
    // END OF - ESC Key implementation



    // Closes with focus out handler
    $("[znt-disclosure_focusout]").each(function () {
      $(this).on('focusout', function(e) {
        if (!$(this).has(e.relatedTarget).length) {
          const $toggleButton = $(this).find("[znt-disclosure_toggle-button]");
          $toggleButton.attr("aria-expanded", false);
          console.log('focusout');
        }
      });
    });
    // END OF - Closes with focus out handler


    // Open the panel on hover
    if ($('[znt-disclosure_hoverable]').length) {
      $('[znt-disclosure_hoverable]').hover(
        function() {
          $(this).find('button').attr('aria-expanded', 'true');
        },
        function() {
          $(this).find('button').attr('aria-expanded', 'false');
        }
      );
    }
    // END OF - Open the panel on hover

    // Dynamic ID
    $("[znt-disclosure_toggle-button]").each(function () {
      // Generate a unique ID using a timestamp and a random number to ensure uniqueness
      const uniqueId = "znt-disclosure_" + Date.now() + "_" + Math.floor(Math.random() * 1000000);
  
      // Setting aria-expanded to false initially
      $(this).attr("aria-expanded", "false");
  
      // Find the closest common ancestor element that contains both the button and the panel
      // Then find the specific panel within that ancestor
      const $closestCommonAncestor = $(this).closest(':has([znt-disclosure_toggle-panel])');
      const $togglePanel = $closestCommonAncestor.find("[znt-disclosure_toggle-panel]");
  
      // Check if a toggle panel was found
      if ($togglePanel.length) {
        // Assign the unique ID to the panel
        $togglePanel.attr("id", uniqueId);
  
        // Set the aria-controls attribute of the button to match the generated unique ID
        $(this).attr("aria-controls", uniqueId);
      }
    });
    // Dynamic ID



    // aria-expanded observer
    // Keeps only one panel opened when there is a hoverable with a non-hoverable button within the same <ul>

    // Check if there's any [znt-disclosure_hoverable] within a <ul>
    $('ul').each(function() {
      if ($(this).find('[znt-disclosure_hoverable]').length > 0) {
        // Target each <ul> that contains [znt-disclosure_hoverable]
        const observerZntDisclosure = new MutationObserver(function(mutations) {
          mutations.forEach(function(mutation) {
            if (mutation.type === 'attributes' && mutation.attributeName === 'aria-expanded') {
              const $target = $(mutation.target);
              if ($target.attr('aria-expanded') === 'true') {
                // Set aria-expanded="false" for other [znt-disclosure_toggle-button] within the same <ul>
                $target.closest('ul').find('[znt-disclosure_toggle-button][aria-expanded="true"]').not($target).attr('aria-expanded', 'false');
              }
            }
          });
        });

        // Observer configuration: watch for attributes changes in descendants
        const configZntDisclosure = { attributes: true, subtree: true, attributeFilter: ['aria-expanded'] };

        // Start observing the current <ul>
        observerZntDisclosure.observe(this, configZntDisclosure);
      }
    });
    // END OF - aria-expanded observer

  }
});

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.0/jquery.min.js