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.
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.
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); });
02. Mega Menu with Featured Card
Mega menuPromo
Next to the link list, the panel promotes one item in a card, such as a new collection. The card is a single link with a heading, and the layout gives the links two thirds of the panel so navigation stays the main job.
var b = document.querySelector('.mm2 > button'), p = document.getElementById('mm2p');
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(); } });
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.
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>
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.
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.
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.
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.