You just browsed 20 Tailwind mega menus. Nucleo is a library of 44,000+ SVG icons in five families (Core, UI, Sharp, Pixel and Micro Bold), with web, Mac and Windows apps to manage them. The All Icons Bundle is $149 with lifetime updates.
The reference build, ported to Tailwind CSS v4: a named <nav>, real <button> triggers with aria-expanded and aria-controls, and a full-width multi-column panel that opens on hover and keyboard focus. The whole open state is one custom variant, tmm01-open:, so every panel, chevron and cascade utility reads a single word. Zero JavaScript.
A travel-airline header whose panels wait 120ms before opening and 250ms before closing, so a pointer sweeping across the bar on its way to the page never strobes three panels in a row. The script only toggles a data-open attribute; every visual state — the warm underline, the fade, the card spring — is a tmm02-open: utility. Once one panel is open, moving to the next swaps instantly.
The diagonal-pointer problem, solved the way big retailers do it: while the pointer is travelling inside the triangle between its last position and the open panel's top corners, neighbouring triggers are ignored. A fleet-operations console draws the live triangle in a dashed SVG overlay so you can watch it work. State is a data-open attribute; every visual is a tmm03-open: utility, including the left-to-right row wipe.
An editorial workspace header whose mega panel is a responsive four-column grid: repeat(auto-fit, minmax(11rem, 1fr)) decides how many columns fit, and each column spans three rows with grid-rows-subgrid so headings, link lists and footer counts line up across columns no matter how long a label wraps. Columns unroll left to right on open. Zero JavaScript.
A docs utility bar whose only mega item sits at the far right — exactly where panels fall off the viewport. The panel is end-aligned to its trigger, capped at min(34rem, 100vw - 2rem), and, where CSS anchor positioning exists, tethered to the trigger with position-try-fallbacks: flip-inline so it flips rather than clips. An invisible hover bridge closes the 8px gap. Zero JavaScript.
The panel paints edge to edge while its content stays aligned to the logo. The trick is which box is the containing block: items are static, so the panel's absolute inset-x-0 resolves against the full-width <header>, and an inner w-[min(72rem,calc(100%-2rem))] mx-auto re-applies the page column. A seasonal garden retailer, with a curtain that opens from the centre outward. Zero JavaScript.
Newsletter
Enjoying these demos? Get new ones by email.
A short email when a new collection ships. Unsubscribe any time.
WCAG 1.4.13 says content that appears on hover or focus must be dismissible. This dark app shell implements the full contract: Escape closes the open panel from anywhere inside it and returns focus to its trigger, aria-expanded tracks the real state, focus leaving the item closes it, and Tab onto a trigger does not throw a panel over the page. The panel only ever renders from [data-open].
A rounded fintech header where the keyboard moves like a spreadsheet. The top bar is one Tab stop with a roving tabindex (Left/Right/Home/End), ArrowDown opens a panel and lands on its first link, and inside the panel Up/Down walk a column while Left/Right jump to the same row of the neighbouring column. Escape always goes back to the trigger. A legend in the panel footer teaches the keys.
The boundary marker for the whole collection: a mega menu is a disclosure, not an ARIA menu. Each trigger is a <button> with aria-expanded and aria-controls; each panel is named by its trigger via aria-labelledby; the current page is marked with aria-current="page" and styled with the aria-[current=page]: variant. A monochrome camera specialist with hard rules and one red accent. Zero JavaScript.
Hover does not exist on a phone, and emulated hover is how mega menus end up needing a double tap on iOS. This mobile storefront drops hover entirely below a fine pointer: one tap toggles a panel, a second tap closes it, and only one panel is open at a time. Panels slide open with an animated grid-rows-[0fr] → grid-rows-[1fr] transition instead of snapping from display: none.
What does a screen-reader user hear when they reach a mega menu? Here: "Study, button, collapsed, 14 links in 4 groups". Each trigger is described by an sr-only summary via aria-describedby, each panel is named by its trigger, and every column is a labelled <section> so heading and landmark navigation work inside it. A university header whose panel resolves out of a blur. Zero JavaScript.
Instead of one panel per item, three triggers share one glass panel that stays open while its content swaps — the continuous feel of a streaming app's header. The panel height animates with grid-rows-[0fr] → data-open:grid-rows-[1fr], and each swapped-in section replays a lateral slide using Tailwind's starting: variant (@starting-style), so the script only flips hidden and two attributes.
The panel is genuinely display: none while closed — not just invisible — and still fades and slides in and out. Tailwind v4 makes the new CSS a class list: transition-discrete lets display transition, and starting:tmm13-open:opacity-0 declares where the entry animation begins. A brutalist coffee-subscription header with hard offset shadows and links that snap in on a steps() clock. Zero JavaScript.
One navigation, two forms, side by side: the desktop mega panel on the left (inside a browser frame that is its own @container, so it collapses when the frame narrows), and the phone drawer on the right, built from native <details name> so only one section opens at a time with no script. On phones the mega columns flatten to a short list of the five links people actually tap. Zero JavaScript.
Newsletter
Enjoying these demos? Get new ones by email.
A short email when a new collection ships. Unsubscribe any time.
A newspaper masthead whose Sections panel pairs three ruled link columns with a featured long read: a lazy-loaded photo that settles from an overscale and blooms from grayscale to colour on hover. Link rows rise from behind their own baseline with a clip-path reveal, like type set into a column. Libre Caslon and Libre Franklin carry the editorial voice. Zero JavaScript.
An operations console where the mega panel doubles as a status board: three columns of tools, and a live rail showing service health, an incident callout and the current deploy. Each health row is a @container child that drops its state label, then its latency, as the rail narrows. A scanline sweeps the panel on open while rows switch on in discrete flickers. Zero JavaScript.
A plant studio's Shop by room panel built as a grid of photo cards: aspect-[4/3] object-cover crops, a New chip where a range has just landed, and a gentle zoom on hover. Cards settle in on a slow, organic stagger and a care-and-setup aside offers the service links. auto-fit decides how many cards fit per row, so six rooms and three pot types use the same markup. Zero JavaScript.
Dense retail navigation done the Swiss way: four ruled columns of up to seven links each, heavy black rules, one red accent, and a footer row of department-wide links. Columns share rows through grid-rows-subgrid so headings sit on one line, and they wipe in strictly left to right on a linear clock. New lines are flagged inline. Zero JavaScript.
The mega panel as a product finder: grouped <fieldset> facets, a budget slider and a live result count announced through role="status". Checkbox rows become selectable chips with Tailwind's has-checked: variant — no custom checkbox markup. A badge on the trigger shows how many filters are active even when the panel is closed, and Clear filters resets everything in one tap.
A stationery shop whose mega panel gives a full third of its width to the offer: a solid amber block with an end-date pill, a one-line headline and a navy CTA, beside three link columns. Hard offset shadows tie the panel to the floating bar, and links pop in with an overshoot, alternate columns lagging for a ripple. Zero JavaScript.
FAQ
Frequently asked questions
How do I build a Tailwind mega menu with no JavaScript?
Demo 01 does it with :focus-within and the sibling combinator instead of a click handler. Each top item is a real <button> inside a named <nav>, and the panel is a sibling element hidden with invisible opacity-0. When focus lands anywhere inside that item group — on the button or any link in the panel — the group-focus-within:visible group-focus-within:opacity-100 utilities reveal it. Hover is layered on with group-hover so pointer users also get it. The important part is that focus, not just hover, drives the open state, so keyboard users reach every link by tabbing. The one thing to watch: because there is no script, there is no close on Escape unless you add it, which is why demo 07 exists. Use the pure-CSS build when the menu is simple and you want zero runtime; reach for a little script once you need Escape or roving focus.
Why does my mega menu close when I move the mouse diagonally toward it?
That is the classic diagonal pointer bug: the cursor leaves the trigger's bounding box on its way down-and-across to the panel, so :hover drops and the panel closes before the pointer arrives. Demo 03 fixes it the way large retailers do, with a safe triangle: while the pointer is inside the trigger, an invisible triangular bridge is drawn from the cursor to the two near corners of the panel, so the pointer is technically always over an open region during the trip. Demo 02 attacks the same problem from timing instead — a 120ms open delay and a 250ms close delay, so a pointer sweeping across several items does not flash every panel open and a brief slip off the edge does not close the one you want. If you only need the cheap fix, add transition-delay on the close state; if the panel sits far below the trigger, the triangle is more reliable.
Should a mega menu use ARIA menu roles or disclosure semantics?
Disclosure, not role="menu". Demo 09 is the boundary marker for the whole set: an ARIA menu is for a list of commands that act immediately, like a right-click menu, and it comes with a strict keyboard contract — arrow keys move, Tab exits the whole widget, Enter fires an action. A mega menu is a panel of links you navigate to, so it is a disclosure: the trigger is a <button> with aria-expanded toggling true and false, and the panel is ordinary content that Tab walks through normally. Applying menu roles to links lies to the screen reader and breaks Tab, because users then expect arrow-only movement that your markup does not deliver. Demo 11 goes further and gives each panel a summary like "Study, button, collapsed, 14 links" so the count is announced. Reserve menu roles for actual command menus; use disclosure for navigation.
How do I make the mega menu panel fade in when it is display:none while closed?
A panel set to display: none cannot transition, because the browser has nothing to animate from — the element is not in the box tree one frame and fully laid out the next. Demo 13 solves this with two modern CSS features. First, @starting-style defines the before-open values (opacity zero, a small translate) that the panel animates away from on first paint. Second, transition-behavior: allow-discrete lets display itself participate in the transition, so the element stays visible through the close animation and only flips to display: none at the end. The payoff is a genuinely removed panel while closed — not merely opacity-0 sitting there catching clicks and tab stops — that still fades in and out. If you need older-browser support, fall back to the visibility plus opacity pattern from demo 01, which transitions but leaves the node in the tree.
What is the right way to handle a mega menu on touch devices?
Hover does not exist on a phone, so a hover-only mega menu forces iOS into its emulated-hover behaviour where the first tap opens and the link needs a second tap — the infamous double tap. Demo 10 switches the interaction to tap to open: the trigger is a <button> that toggles aria-expanded, the first tap opens the panel, and the links inside are then single-tap targets. The cleanest way to split behaviour by device is the @media (hover: hover) query — apply the group-hover open rules only where a real pointer exists, and rely on the explicit toggle everywhere else. Demo 14 shows the matching layout decision: the sprawling multi-column desktop panel has to collapse into a stacked accordion on narrow screens, because a four-column grid does not fit 375px. Do not just shrink the desktop panel; restructure it into vertical disclosure sections.
How do I keep a full-width mega menu panel aligned to the content inside a contained header?
The conflict is that the panel wants to paint edge to edge across the viewport while its columns must line up with the logo, which sits inside a centred max-width container. Demo 06 resolves it by choosing which box is the positioning context. The header bar keeps its centred container for the logo and nav items, but the panel is taken out of that container — positioned against the full-width header — so its background and border stretch the whole screen. Inside the panel, a second centred container with the same max-width and horizontal padding as the header re-aligns the actual link columns under the nav. The common mistake is giving the panel width: 100vw with a negative margin hack; that breaks the moment a scrollbar changes the viewport width. Letting a full-bleed parent own the background and an inner max-width wrapper own the content is the stable version.
My mega menu panel gets cut off at the right edge of the screen — how do I fix it?
When a trigger sits near the right edge, a panel anchored to the trigger's left runs straight off the viewport. Demo 05 handles it with CSS anchor positioning: the trigger is declared an anchor, the panel is tied to it, and position-try-fallbacks lists alternate placements so the browser flips the panel to open from the right edge inward when the default position would overflow. That keeps the alignment logic in CSS instead of a resize-listener measuring getBoundingClientRect on every open. Where anchor positioning is not available, the older fallback is to align that one panel's right edge to the trigger — effectively right: 0 on the panel relative to a positioned item — so it grows leftward. Either way, test the rightmost item specifically, because a panel that looks fine under a centred nav item is exactly the one that clips when you move it to the end of the bar.
How do keyboard and screen-reader users operate these mega menus?
Three demos cover the contract. Demo 07 implements WCAG 1.4.13: content shown on hover or focus must be dismissible, so Escape closes the open panel and returns focus to the trigger that opened it — without the focus return, a keyboard user is dumped at the top of the document. Demo 08 adds a roving tabindex so the top bar is a single Tab stop and arrow keys move between items like spreadsheet cells, with Down entering the panel and arrows crossing its columns, which keeps a 40-link menu from costing 40 Tab presses. Demo 11 handles the announcement: each trigger carries aria-expanded and a label that includes the link count, so a screen reader says the name, that it is collapsed or expanded, and how many links wait inside. The baseline every demo shares is a real <button> trigger and aria-expanded — skip those and the menu is invisible to assistive tech no matter how good it looks.