<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 znt-disclosure" aria-labelledby="znt-nav_01">
        <p id="znt-nav_01" class="visually-hidden">
          Main
        </p>
        <a href="javascript:void(0);" 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 
          aria-controls="znt-mobile-panel_01"
          class="znt-mobile-menu-item znt-disclosure_button znt-tablet" 
          hidden>
          <span class="visually-hidden">
            Menu
          </span>
        </button>
        <ul id="znt-mobile-panel_01" class="znt-nav-list znt-disclosure_panel">
          <li class="znt-nav-item has-link znt-disclosure">
            <a href="javascript:void(0);">Link + Button</a>
            <button 
              aria-controls="znt-menu_01"
              class="znt-mega-menu-item znt-disclosure_button">
              <span class="visually-hidden">
                Toggle submenu
              </span>
            </button>
            <div 
              id="znt-menu_01"
              class="znt-mega-menu-panel znt-disclosure_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">
                      WCAG 2.2 Core Principles
                    </h2>
                    <ul aria-labelledby="znt-mega-menu-links_01" class="znt-mega-menu-links">
                      <li><a href="https://www.w3.org/WAI/WCAG22/quickref/#perceivable" target="_blank">Perceivable</a></li>
                      <li><a href="https://www.w3.org/WAI/WCAG22/quickref/#operable" target="_blank">Operable</a></li>
                      <li><a href="https://www.w3.org/WAI/WCAG22/quickref/#understandable" target="_blank">Understandable</a></li>
                      <li><a href="https://www.w3.org/WAI/WCAG22/quickref/#robust" target="_blank">Robust</a></li>
                    </ul>
                  </div>
                  <div class="znt-col-4-12">
                    <div class="znt-card">
                      <img src="https://assets-global.website-files.com/64a6dd1a72b0c8b654f1d0be/65e9de124bf99bef0cea47bf_shopify-inaccessible.webp" alt="" class="znt-card-image">
                      <div class="znt-card-body">
                        <h2 class="znt-card-heading">
                          <a href="https://www.zenythgroup.com/post/unlocking-shopify-accessibility-to-boost-sales-avoid-lawsuits" target="_blank">
                            Unlocking Shopify Accessibility to Boost Sales & Avoid Lawsuits
                          </a>
                        </h2>
                        <p class="znt-card-copy">
                          Welcome to the digital era where inclusivity isn't just a buzzword—it's your ticket to unlocking untapped market potential and safeguard.
                        </p>
                      </div>
                    </div>
                  </div>
                  <div class="znt-col-4-12">
                    <div class="znt-card">
                      <img src="https://assets-global.website-files.com/64a6dd1a72b0c8b654f1d0be/65e9fa71aa591b41d2440998_webflow-storefront.png" alt="" class="znt-card-image">
                      <div class="znt-card-body">
                        <h2 class="znt-card-heading">
                          <a href="https://www.zenythgroup.com/post/making-ecommerce-work-for-everyone-with-zenyth-webflow" target="_blank">
                            Making eCommerce Work for Everyone with Zenyth & Webflow
                          </a>
                        </h2>
                        <p class="znt-card-copy">
                          Imagine stepping into the world of eCommerce, where every click, every page, and every product is within easy reach.
                        </p>
                      </div>
                    </div>
                  </div>
                </div>
              </div>
            </div>
          </li>
          <li class="znt-nav-item znt-disclosure">
            <button 
              aria-controls="znt-menu_02"
              class="znt-mega-menu-item znt-disclosure_button">
              Button Item
            </button>
            <div 
              id="znt-menu_02"
              class="znt-mega-menu-panel znt-disclosure_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">
                      WCAG 2.2 SC Overview
                    </h2>
                    <ul aria-labelledby="znt-mega-menu-links_02" class="znt-mega-menu-links">
                      <li><a href="https://www.w3.org/WAI/WCAG22/quickref/" target="_blank">Quick Reference</a></li>
                      <li><a href="https://www.w3.org/WAI/WCAG22/Understanding/" target="_blank">Understanding WCAG 2.2</a></li>
                      <li><a href="https://www.w3.org/WAI/WCAG22/Techniques/" target="_blank">WCAG Techniques</a></li>
                      <li><a href="https://www.w3.org/WAI/standards-guidelines/wcag/new-in-22/" target="_blank">What's New in 2.2</a></li>
                      <li><a href="https://www.w3.org/WAI/test-evaluate/" target="_blank">Testing and Evaluation</a></li>
                      <li><a href="https://www.w3.org/WAI/policies/" target="_blank">Global Policies</a></li>
                    </ul>
                  </div>
                  <div class="znt-col-4-12">
                    <div class="znt-card">
                      <img src="https://assets-global.website-files.com/64a6dd1a72b0c8b654f1d0be/65d367498403d367e007950b_design-vs-accessibility-css-visually-hidden-class.webp" alt="" class="znt-card-image">
                      <div class="znt-card-body">
                        <h2 class="znt-card-heading">
                          <a href="https://www.zenythgroup.com/post/design-vs-accessibility-and-the-css-visually-hidden-class" target="_blank">
                            Design vs. accessibility and the CSS visually-hidden class
                          </a>
                        </h2>
                        <p class="znt-card-copy">
                          We look using the CSS visually-hidden utility class to make elements available to users of assistive technologies without impacting design.
                        </p>
                      </div>
                    </div>
                  </div>
                  <div class="znt-col-4-12">
                    <div class="znt-card">
                      <img src="https://assets-global.website-files.com/64a6dd1a72b0c8b654f1d0be/65b2e6e42ba6aa41b894e850_understanding-html-landmarks-how-to-apply.webp" alt="" class="znt-card-image">
                      <div class="znt-card-body">
                        <h2 class="znt-card-heading">
                          <a href="https://www.zenythgroup.com/post/understanding-html-landmarks-and-how-to-apply-them" target="_blank">
                            Understanding HTML landmarks and how to apply them
                          </a>
                        </h2>
                        <p class="znt-card-copy">
                          We demystify HTML landmarks, discuss the nuances of different types, and show how to use them to help screen reader users navigate a site.
                        </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-disclosure_button:not([aria-expanded="true"]):not(.znt-tablet) + .znt-disclosure_panel { display: none; }
@media(max-width: 1025px) { .znt-disclosure_button.znt-tablet:not([aria-expanded="true"]) + .znt-disclosure_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: 4px;
  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; }



/* Disclosure focus when it has a and button */
.znt-disclosure:has(> a, > button) {
  display: flex;
}

.znt-disclosure:has(> a, > button) > a {
  padding-right: 8px !important;
  margin-right: 32px;
}

.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_button:not([aria-expanded="true"]) + .znt-disclosure_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: top 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_button").length) {

    // Base aria-expanded toggler
    $(".znt-disclosure_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_panel, for disclosure search components 
          const $togglePanel = $(this).siblings(".znt-disclosure_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_button").each(function () {
          $(this).siblings('.znt-disclosure_panel').find(':focus').closest('.znt-disclosure_panel').siblings('.znt-disclosure_button').focus();
          $(this).attr("aria-expanded", false);
        });
      }
    });
    // END OF - ESC Key implementation



    // Closes with focus out handler
    $(".znt-disclosure").each(function () {
      $(this).on('focusout', function(e) {
        if (!$(this).has(e.relatedTarget).length) {
          const $toggleButton = $(this).find(".znt-disclosure_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





    // 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_button within the same <ul>
                $target.closest('ul').find('.znt-disclosure_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