<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
}
});
This Pen doesn't use any external CSS resources.