How to Create a Mega Menu for a Website With HTML and CSS (No Plugin Needed)
If your site has more than about 25 pages, a single-level dropdown starts to hurt. Links get buried, users scroll inside tiny menus, and your best content never gets clicked. A mega menu fixes that by showing an entire section of your site in one wide panel, organised into columns, with headings, icons and featured links. This tutorial shows how to design a mega menu from the information architecture stage right through to production-ready HTML, CSS and a small JavaScript layer for keyboard and touch users. No page builder, no jQuery, no 200 KB plugin. Everything here works in every modern browser and degrades gracefully. What a Mega Menu Is (and When You Actually Need One) A mega menu is a large, rectangular dropdown panel that opens from a top-level navigation item and displays many links at once, grouped into visible columns and categories. Nielsen Norman Group research has consistently shown that these panels outperform traditional cascading dropdowns because everything is visible in one glance instead of hidden behind hover-and-pray sub-levels. Use a mega menu when: You have 4 or more top-level sections, each with 5 to 20 sub-pages. Your categories benefit from visual grouping (product families, documentation topics, industries, resource types). You want to promote specific pages such as pricing, a free trial, a flagship guide or a new release. Analytics show users going straight to search because the nav does not surface what they need. Skip it when you have fewer than 15 destination pages. A mega menu on a small site is just noise. Mega Menu vs Standard Dropdown Criteria Standard dropdown Mega menu Links visible at once 5 to 10 15 to 40 Grouping and labels Flat list Column headings, icons, descriptions Sub-levels needed Often 2 or 3 deep One level, no cascading Promotion space None Featured card, CTA, image Risk Hidden content Overload if unstructured Step 1: Design the Structure Before You Write Any Code The biggest mistake in mega menu projects is opening a code editor first. Spend 30 minutes on paper or in a spreadsheet instead. Export your page list from your sitemap or CMS. Group pages into 3 to 5 columns per top-level item. Each column gets a short, noun-based heading such as “Hosting”, “Developer tools”, “By industry”. If a column needs more than 8 links, split it or move something to a landing page. Order links by demand, not alphabetically. Put your top traffic and top revenue pages first in each column. Reserve one slot for a featured block per panel: latest release, popular guide, pricing, demo booking. Write link labels as users would search them. “API documentation” beats “Resources for builders”. Cap the panel at roughly 30 links. Beyond that, add a “View all” link to a full section index page. Visual rules that make a mega menu readable Keep panel height under about 480 px so nothing gets cut off on a 13-inch laptop. Use one accent colour for hover states, not five. Icons should be 20 to 24 px, monochrome, and only used when they help identification. Decorative icons on every link slow scanning. Give each link 8 to 12 px vertical padding so touch targets stay usable. Left-align everything. Centered columns are much harder to scan. Add a soft drop shadow and a light top border so the panel reads as a layer above the page. Step 2: The HTML Skeleton Semantic markup does most of the accessibility work for you. Use a <nav>, a real list, and a <button> for anything that opens a panel. Never use a bare <div> or an empty <a href=”#”> as a trigger. <nav class=”mm” aria-label=”Main navigation” data-mega> <a class=”mm-logo” href=”/”>Acme</a> <button class=”mm-burger” aria-expanded=”false” aria-controls=”mm-list”> <span class=”sr-only”>Open menu</span> <span class=”mm-burger-bars” aria-hidden=”true”></span> </button> <ul class=”mm-list” id=”mm-list”> <li class=”mm-item mm-has-panel”> <button class=”mm-trigger” aria-expanded=”false” aria-controls=”panel-products”> Products <span class=”mm-caret” aria-hidden=”true”></span> </button> <div class=”mm-panel” id=”panel-products”> <div class=”mm-grid”> <div class=”mm-col”> <h2 class=”mm-heading”>Hosting</h2> <ul class=”mm-links”> <li><a href=”/shared”> <svg class=”mm-ico” aria-hidden=”true” viewBox=”0 0 24 24″><use href=”#i-server”></use></svg> <span>Shared hosting<span class=”mm-desc”>Best for small sites</span></span> </a></li> <li><a href=”/vps”><span>VPS</span></a></li> <li><a href=”/dedicated”><span>Dedicated servers</span></a></li> </ul> </div> <div class=”mm-col”> <h2 class=”mm-heading”>Developer tools</h2> <ul class=”mm-links”> <li><a href=”/cli”><span>CLI</span></a></li> <li><a href=”/api”><span>REST API</span></a></li> <li><a href=”/webhooks”><span>Webhooks</span></a></li> </ul> </div> <div class=”mm-col”> <h2 class=”mm-heading”>By use case</h2> <ul class=”mm-links”> <li><a href=”/ecommerce”><span>Ecommerce</span></a></li> <li><a href=”/agencies”><span>Agencies</span></a></li> <li><a href=”/saas”><span>SaaS teams</span></a></li> </ul> </div> <div class=”mm-col mm-featured”> <p class=”mm-tag”>New</p> <h2 class=”mm-feat-title”>Edge deploys in 12 seconds</h2> <p class=”mm-desc”>See the benchmark and migration guide.</p> <a class=”mm-btn” href=”/edge”>Read the guide</a> </div> </div> </div> </li> <li class=”mm-item”><a class=”mm-link” href=”/pricing”>Pricing</a></li> <li class=”mm-item”><a class=”mm-link” href=”/contact”>Contact</a></li> </ul> </nav> Notes on the markup: aria-expanded tells screen readers whether the panel is open. JavaScript flips it. aria-controls links the trigger to the panel ID. Column headings use real heading tags so the panel has an outline. If your page heading levels conflict, use <p class=”mm-heading”> plus role=”group” and aria-label on the column instead. Icons carry aria-hidden=”true” because the text already labels the link. Step 3: The CSS That Does the Heavy Lifting The trick for a full-width panel is simple: the parent <nav> is position: relative, the list items stay position: static, and the panel is absolutely positioned with left: 0; right: 0. That stretches the panel edge to edge no matter where the trigger sits. :root{ –mm-ink:#16181d; –mm-muted:#6b7280; –mm-accent:#0b5fff; –mm-line:#e5e7eb; –mm-radius:10px; } .mm{ position:relative; display:flex; align-items:center; gap:24px; padding:0 24px; background:#fff; border-bottom:1px solid var(–mm-line); font-family:system-ui,-apple-system,”Segoe UI”,sans-serif; } .mm-list{display:flex;gap:2px;margin:0;padding:0;list-style:none} .mm-item{position:static} .mm-trigger,.mm-link{ display:flex;align-items:center;gap:7px; padding:20px 14px; background:none;border:0; font:inherit;font-weight:600;font-size:.95rem; color:var(–mm-ink);text-decoration:none;cursor:pointer; } .mm-trigger:hover,.mm-link:hover, .mm-trigger[aria-expanded=”true”]{color:var(–mm-accent)} .mm-caret{ width:7px;height:7px; border-right:2px solid currentColor; border-bottom:2px solid currentColor; transform:rotate(45deg) translateY(-2px); transition:transform .2s ease; } .mm-trigger[aria-expanded=”true”] .mm-caret{transform:rotate(225deg) translateY(2px)} /* The panel */ .mm-panel{ position:absolute;left:0;right:0;top:100%; z-index:60; padding:34px 24px 38px; background:#fff; border-top:1px solid var(–mm-line); box-shadow:0 26px 50px rgba(15,23,42,.12); opacity:0;visibility:hidden; transform:translateY(-10px); transition:opacity .18s ease,transform .18s ease,visibility .18s; } /* Three ways to open: mouse, keyboard, JS class */ .mm-has-panel:hover > .mm-panel, .mm-has-panel:focus-within > .mm-panel, .mm-has-panel.is-open > .mm-panel{ opacity:1;visibility:visible;transform:translateY(0); } /* Columns */ .mm-grid{ display:grid; grid-template-columns:repeat(4,minmax(0,1fr)); gap:34px; max-width:1200px;margin:0 auto; } .mm-heading{ margin:0 0 14px; font-size:.72rem;font-weight:700; letter-spacing:.09em;text-transform:uppercase; color:var(–mm-muted); } .mm-links{margin:0;padding:0;list-style:none} .mm-links li+li{margin-top:4px} .mm-links a{ display:flex;gap:11px;align-items:flex-start; padding:8px 9px;border-radius:var(–mm-radius); color:var(–mm-ink);text-decoration:none;font-size:.93rem; } .mm-links a:hover,.mm-links a:focus-visible{background:#f2f6ff;color:var(–mm-accent)} .mm-ico{flex:0 0 20px;width:20px;height:20px;fill:none;stroke:currentColor;stroke-width:1.6} .mm-desc{display:block;margin-top:2px;font-size:.8rem;font-weight:400;color:var(–mm-muted)} /* Featured card */ .mm-featured{background:#f7f9fc;border:1px solid var(–mm-line);border-radius:14px;padding:22px} .mm-tag{display:inline-block;margin:0 0
How to Create a Mega Menu for a Website With HTML and CSS (No Plugin Needed) Read More »









