UI element
The mega menu
A mega menu that opens on hover with intent and behaves on a keyboard.
- By
- Caleb and Ryan, the founders
- Updated
- August 28, 2026
- Version
- 1.0, in the library
- Claude Code
- Cursor
The What we do menu from this site's header: a disclosure, not an ARIA menubar, with hover intent timers so it never flickers, arrow keys into the links, Escape back to the button, and every way it should close (outside click, focus leaving, scroll, a route change). Three columns and a featured slot, fed from one content file, with the mobile accordion that replaces it below a breakpoint.
Built, documented, running.
Part of the working library we deploy from on every engagement.
Bring this into a project- Complete and documented: the same files we run ourselves.
- Deployed and tuned to your stack as part of an engagement.
The file
Draft excerpt// A disclosure (button + region), NOT an ARIA menubar: menubar semantics// are for application menus, and screen readers treat them that way.const OPEN_DELAY = 90;const CLOSE_DELAY = 260; // long enough to cross the gap under the pillexport function MegaMenu({ label, columns, featured }: Props) { const [open, setOpen] = useState(false); // hover with intent, click, ArrowDown into the links, Escape back, // outside click, focus-out, scroll and route change all close it. ...}
What is inside
5 items. Includes deployment guide.
MegaMenu.tsxThe disclosure: hover intent, keyboard, every close condition.MegaMenu.module.cssThe panel material and the per-item hover surface.menu.tsThe content file: columns, items with taglines, one featured slot.MobileAccordion.tsxThe same content as an accordion inside a mobile panel.GUIDE.mdWhy a disclosure and not a menubar, and the gap bug that took a day.
Who it is for
- Your header has outgrown five links and the menu you tried closes when the pointer crosses the gap.
- You want the keyboard and screen-reader behaviour right without reading the ARIA practices twice.
- You want the mobile version to be the same content, not a second menu to maintain.
Requirements
- React 18 or later
- A header the panel can position under
Install
- 01
Copy the four files into your header's folder.
- 02
Fill menu.ts with your columns. Every item needs a real destination.
- 03
Mount MegaMenu in your header row and MobileAccordion in your mobile panel.
Where this sits
This system
The mega menu
In the library, running.
Pairs with
An hour to mount it in your header with the person who built it.
In your stack
The audit finds which system earns its place first; we install and tune it around how you work.
Questions
- Why not a menubar?
- Because a site navigation is a disclosure: a button that opens a region of links. Menubar semantics belong to application menus and confuse screen readers on a website.
- Does it depend on your header?
- No. It positions under whatever element you mount it in.
- What is the gap bug?
- The pointer crossing the space between the button and the panel fired a close; the panel now owns that gap as padding. The guide has the whole story.
- What is the next step up?
- The install call, if you want it mounted with you on a call; or the Design page, for the rest of the header.
Changelog
- August 28, 2026In the library. Version 1.0 runs in our own operation.
Related
- Featured
Skill
Code review skill with a pattern database
A review pass that knows your framework's failure patterns before it reads your diff
Works with Claude Code, Cursor.
Built and running UI element
The scroll scene shell
A sticky scene scrubbed by scroll, with the static fallback built in
Works with Claude Code, Cursor.
Built and runningSkill
Code review checklist pack
Reviews that check what your team actually gets burned by
Works with Claude Code, Cursor.
Built and running