SolutionsCase StudiesAI ToolsResourcesAboutContact
Get Your Free AI Automation Audit Book a Free 30-Minute Strategy Call
Playground~/frontend Open editor

~/css/mega-menus

7 CSS Mega Menus

3 Pure CSS4 with JSPublished 2026-10-05Free · no sign-up

Seven mega menus that work with the keyboard: a panel of link columns, links with a featured promotion, a category list that drives sub-panels, links with icons and descriptions, a hover menu with a delay, a mega menu that becomes an accordion on phones and a script-free panel.

01. Mega Menu with Link Columns

Mega menuDisclosure

A Products button opens a wide panel of links in columns. It is a disclosure (a button with aria-expanded controlling a region), not an ARIA menu, because the panel holds ordinary links that should be reached with Tab. Escape closes it and returns focus.

View code
<nav class="mm1" aria-label="Main"><ul class="top"><li><button aria-expanded="false" aria-controls="mm1p">Products</button><div id="mm1p" class="panel" hidden><div><h3>Sell</h3><a href="#store">Online store</a><a href="#pos">Point of sale</a></div><div><h3>Market</h3><a href="#email">Email</a><a href="#social">Social ads</a></div><div><h3>Manage</h3><a href="#stock">Stock</a><a href="#reports">Reports</a></div></div></li><li><a href="#pricing">Pricing</a></li></ul></nav>
.mm1 { position: relative; width: 560px; max-width: 100%; font: 14px Inter, system-ui, sans-serif; }
.mm1 .top { display: flex; gap: 6px; margin: 0; padding: 8px; list-style: none; border: 1px solid #e4e7ec; border-radius: 12px; background: #fff; }
.mm1 .top > li > button, .mm1 .top > li > a { display: block; padding: 8px 12px; border: 0; border-radius: 8px; background: none; color: #101828; font: 600 14px Inter, system-ui, sans-serif; text-decoration: none; cursor: pointer; }
.mm1 button[aria-expanded=true] { background: #f2f4f7; }
.mm1 button::after { content: ""; display: inline-block; width: 6px; height: 6px; margin-left: 8px; border-right: 2px solid currentColor; border-bottom: 2px solid currentColor; transform: translateY(-3px) rotate(45deg); }
.mm1 .panel { position: absolute; left: 0; right: 0; top: calc(100% + 6px); display: grid; grid-template-columns: repeat(auto-fit, minmax(130px, 1fr)); gap: 14px; padding: 16px; box-sizing: border-box; border: 1px solid #e4e7ec; border-radius: 12px; background: #fff; box-shadow: 0 16px 32px -16px rgba(16,24,40,.3); }
.mm1 .panel[hidden] { display: none; }
.mm1 h3 { margin: 0 0 6px; color: #475467; font-size: 12px; text-transform: uppercase; letter-spacing: .06em; }
.mm1 .panel a { display: block; padding: 5px 0; color: #101828; text-decoration: none; } .mm1 .panel a:hover { color: #6941c6; }
.mm1 a:focus-visible, .mm1 button:focus-visible { outline: 3px solid #d6bbfb; outline-offset: 2px; border-radius: 6px; }
var b = document.querySelector('.mm1 button'), p = document.getElementById('mm1p');
function set(o) { b.setAttribute('aria-expanded', o); p.hidden = !o; }
b.onclick = function () { set(b.getAttribute('aria-expanded') !== 'true'); };
document.addEventListener('keydown', function (e) { if (e.key === 'Escape' && !p.hidden) { set(false); b.focus(); } });
document.addEventListener('click', function (e) { if (!e.target.closest('.mm1 .top > li:first-child')) set(false); });

03. Category List Driving a Panel

Mega menuCategories

Big catalogues use a category list on the left that changes the links on the right when a category is hovered or focused. The categories are buttons with aria-expanded, so keyboard users can open each one, and only one sub-panel is visible at a time.

View code
<div class="mm3"><ul class="cats"><li><button aria-expanded="true" aria-controls="mm3a">Kitchen</button></li><li><button aria-expanded="false" aria-controls="mm3b">Bedroom</button></li><li><button aria-expanded="false" aria-controls="mm3c">Garden</button></li></ul><div class="subs"><ul id="mm3a"><li><a href="#pans">Pans</a></li><li><a href="#knives">Knives</a></li><li><a href="#mugs">Mugs</a></li></ul><ul id="mm3b" hidden><li><a href="#bedding">Bedding</a></li><li><a href="#lamps">Lamps</a></li></ul><ul id="mm3c" hidden><li><a href="#planters">Planters</a></li><li><a href="#tools">Tools</a></li></ul></div></div>
.mm3 { display: grid; grid-template-columns: 130px 1fr; width: 420px; max-width: 100%; border: 1px solid #e4e7ec; border-radius: 14px; overflow: hidden; background: #fff; font: 14px Inter, system-ui, sans-serif; }
.mm3 ul { margin: 0; padding: 8px; list-style: none; }
.mm3 .cats { background: #f9fafb; border-right: 1px solid #e4e7ec; }
.mm3 .cats button { width: 100%; padding: 9px 10px; border: 0; border-radius: 8px; background: none; color: #344054; font: 600 14px Inter, system-ui, sans-serif; text-align: left; cursor: pointer; }
.mm3 .cats [aria-expanded=true] { background: #fff; color: #101828; box-shadow: 0 1px 2px rgba(16,24,40,.1); }
.mm3 .subs a { display: block; padding: 8px 10px; border-radius: 8px; color: #101828; text-decoration: none; } .mm3 .subs a:hover { background: #f2f4f7; }
.mm3 button:focus-visible, .mm3 a:focus-visible { outline: 3px solid #84adff; outline-offset: 1px; }
var bs = document.querySelectorAll('.mm3 .cats button');
function open(b) { bs.forEach(function (x) { var on = x === b; x.setAttribute('aria-expanded', on); document.getElementById(x.getAttribute('aria-controls')).hidden = !on; }); }
bs.forEach(function (b) { b.onclick = function () { open(b); }; b.onmouseenter = function () { open(b); }; });

04. Mega Menu with Icons and Descriptions

Mega menuIcons

For software products each link gets an icon, a name and one line explaining it, so people can find the right page without guessing. The icon is decorative, the name is the link text and the description is part of the link.

View code
<div class="mm4"><a href="#analytics"><span class="ic" aria-hidden="true">📊</span><span><b>Analytics</b><small>See what drives sales</small></span></a><a href="#automations"><span class="ic" aria-hidden="true">⚙</span><span><b>Automations</b><small>Rules that run themselves</small></span></a><a href="#inbox"><span class="ic" aria-hidden="true">✉</span><span><b>Inbox</b><small>Every message in one place</small></span></a><a href="#api"><span class="ic" aria-hidden="true">⌘</span><span><b>API</b><small>Build your own tools</small></span></a></div>
.mm4 { display: grid; grid-template-columns: repeat(auto-fit, minmax(170px, 1fr)); gap: 4px; width: 460px; max-width: 100%; box-sizing: border-box; padding: 10px; border: 1px solid #263048; border-radius: 14px; background: #111727; font-family: Inter, system-ui, sans-serif; }
.mm4 a { display: flex; gap: 10px; padding: 10px; border-radius: 10px; text-decoration: none; }
.mm4 a:hover { background: #1b2238; }
.mm4 .ic { flex: none; display: grid; place-items: center; width: 34px; height: 34px; border-radius: 8px; background: #1e2546; font-size: 16px; }
.mm4 b { display: block; color: #f8fafc; font-size: 14px; } .mm4 small { color: #94a3b8; font-size: 12px; }
.mm4 a:focus-visible { outline: 2px solid #818cf8; outline-offset: 1px; }

05. Hover with Delay, Click and Keys

Mega menuHover intent

Opens on hover after a short delay, so moving the pointer across the bar does not flash panels, and stays open briefly after the pointer leaves so diagonal moves into the panel do not close it. Click and keyboard work too, and Escape always closes.

View code
<nav class="mm5" aria-label="Main"><div class="it"><button aria-expanded="false" aria-controls="mm5p">Resources</button><div id="mm5p" class="panel" hidden><a href="#guides">Guides</a><a href="#webinars">Webinars</a><a href="#templates">Templates</a></div></div><a href="#blog">Blog</a></nav>
.mm5 { display: flex; gap: 6px; width: 380px; max-width: 100%; padding: 8px; box-sizing: border-box; border: 1px solid #e4e7ec; border-radius: 12px; background: #fff; font: 600 14px Inter, system-ui, sans-serif; }
.mm5 .it { position: relative; }
.mm5 button, .mm5 > a { display: block; padding: 8px 12px; border: 0; border-radius: 8px; background: none; color: #101828; font: inherit; text-decoration: none; cursor: pointer; }
.mm5 button[aria-expanded=true] { background: #f2f4f7; }
.mm5 .panel { position: absolute; left: 0; top: calc(100% + 8px); display: grid; min-width: 180px; padding: 8px; border: 1px solid #e4e7ec; border-radius: 12px; background: #fff; box-shadow: 0 16px 28px -14px rgba(16,24,40,.3); }
.mm5 .panel[hidden] { display: none; }
.mm5 .panel a { padding: 8px 10px; border-radius: 6px; color: #344054; font-weight: 500; text-decoration: none; } .mm5 .panel a:hover { background: #f2f4f7; }
.mm5 a:focus-visible, .mm5 button:focus-visible { outline: 3px solid #84adff; outline-offset: 1px; }
var it = document.querySelector('.mm5 .it'), b = it.querySelector('button'), p = document.getElementById('mm5p'), t;
function set(o) { b.setAttribute('aria-expanded', o); p.hidden = !o; }
it.addEventListener('mouseenter', function () { clearTimeout(t); t = setTimeout(function () { set(true); }, 150); });
it.addEventListener('mouseleave', function () { clearTimeout(t); t = setTimeout(function () { set(false); }, 300); });
b.onclick = function () { clearTimeout(t); set(b.getAttribute('aria-expanded') !== 'true'); };
document.addEventListener('keydown', function (e) { if (e.key === 'Escape' && !p.hidden) { set(false); b.focus(); } });

06. Mega Menu That Becomes an Accordion

Mega menuResponsive

On wide containers the groups show side by side as a mega panel; on narrow ones each group heading becomes a collapsible details element, which is how mega menus should behave inside a mobile menu. The switch is a container query.

View code
<div class="mm6"><div class="in"><details open><summary>Learn</summary><a href="#docs">Docs</a><a href="#courses">Courses</a></details><details open><summary>Company</summary><a href="#about">About</a><a href="#jobs">Jobs</a></details><details open><summary>Help</summary><a href="#support">Support</a><a href="#status">Status</a></details></div></div>
.mm6 { width: 520px; max-width: 100%; container-type: inline-size; font: 14px Inter, system-ui, sans-serif; }
.mm6 .in { display: grid; padding: 8px; border: 1px solid #263048; border-radius: 14px; background: #111727; }
.mm6 summary { padding: 10px; color: #f8fafc; font-weight: 700; cursor: pointer; }
.mm6 a { display: block; padding: 6px 10px 6px 22px; color: #cbd5e1; text-decoration: none; } .mm6 a:hover { color: #fff; }
.mm6 details + details { border-top: 1px solid #263048; }
.mm6 :focus-visible { outline: 2px solid #93c5fd; outline-offset: 1px; border-radius: 6px; }
@container (min-width: 460px) {
  .mm6 .in { grid-template-columns: repeat(3, 1fr); }
  .mm6 details + details { border-top: 0; }
  .mm6 summary { pointer-events: none; list-style: none; color: #94a3b8; font-size: 12px; text-transform: uppercase; letter-spacing: .06em; }
  .mm6 summary::-webkit-details-marker { display: none; }
  .mm6 a { padding-left: 10px; }
}

07. CSS-Only Panel with :focus-within

Mega menuNo JS

A panel that opens on hover and stays open while any link inside has keyboard focus, through :focus-within, with no script. It is a progressive base: add the button-based script from the other demos for touch screens and screen reader announcements.

View code
<nav class="mm7" aria-label="Main"><div class="it"><a href="#solutions" class="trig">Solutions</a><div class="panel"><a href="#retail">Retail</a><a href="#food">Food and drink</a><a href="#services">Services</a></div></div></nav>
.mm7 { width: 320px; max-width: 100%; padding: 8px; box-sizing: border-box; border: 1px solid #e4e7ec; border-radius: 12px; background: #fff; font: 600 14px Inter, system-ui, sans-serif; }
.mm7 .it { position: relative; display: inline-block; }
.mm7 .trig { display: block; padding: 8px 12px; border-radius: 8px; color: #101828; text-decoration: none; }
.mm7 .panel { position: absolute; left: 0; top: 100%; display: grid; min-width: 180px; margin-top: 6px; padding: 8px; border: 1px solid #e4e7ec; border-radius: 12px; background: #fff; box-shadow: 0 16px 28px -14px rgba(16,24,40,.3); visibility: hidden; opacity: 0; transform: translateY(-4px); transition: opacity .15s, transform .15s, visibility .15s; }
.mm7 .it:hover .panel, .mm7 .it:focus-within .panel { visibility: visible; opacity: 1; transform: none; }
.mm7 .panel a { padding: 8px 10px; border-radius: 6px; color: #344054; font-weight: 500; text-decoration: none; } .mm7 .panel a:hover { background: #f2f4f7; }
.mm7 a:focus-visible { outline: 3px solid #84adff; outline-offset: 1px; }

About these CSS Mega Menus

Disclosure, not menu

A mega menu full of links is a disclosure: a button with aria-expanded that shows and hides a region. ARIA role="menu" is for application menus and changes how keys work, which confuses people browsing a site.

Escape and click outside

Close the panel with Escape and return focus to its button, and close it when a click lands outside. These are the two exits people expect.

Hover needs patience

If the panel opens on hover, add a short delay before opening and closing, so moving the pointer across the bar or diagonally into the panel does not flash or snap it shut.

Plan the mobile version

Columns of links do not fit a phone. Inside the mobile menu, each group becomes a collapsible section, which details and summary provide without script.

Frequently asked questions

Should mega menus open on hover or click?

Click is more reliable and works on touch; hover with a delay can be added for mouse users.

How many links is too many?

If people need to read a menu like a page, split it. Group links and keep each group short.

Is the CSS-only version enough?

It works with mouse and keyboard, but a button with aria-expanded is needed for touch and screen reader users.