Header Menu
The menu behind a site header's menu button. A sheet that opens under the header instead of over it, follows the finger and closes on a swipe.
Underlay
At desktop width the panel stays put underneath and the page slides away from it, rounding its corners and dimming as it goes. Below that it is an ordinary full width sheet. Open it, then resize the window to see both.
Fixed Underlay Navigation
✱Straight
Flush with the edge and without chrome, like a page of its own. The header stays in view and the button turns into a cross.
A header that keeps its menu in reach
Open the menu and swipe it away, or press the cross.
Floating
An inset rounded card with a soft shadow, for sites whose pages float on a background.
A header that keeps its menu in reach
Open the menu and swipe it away, or press the cross.
Glass
Translucent and blurred, so the page stays readable behind the menu. It comes from the left here.
A header that keeps its menu in reach
Open the menu and swipe it away, or press the cross.
Full
Drops from the top across the whole width, for a menu that takes over the screen.
A header that keeps its menu in reach
Open the menu and swipe it away, or press the cross.
Anatomy
Import all parts and piece them together.
<script setup>
import {
HeaderMenu,
HeaderMenuBurger,
HeaderMenuClose,
HeaderMenuPage,
HeaderMenuPageContent,
HeaderMenuPanel,
HeaderMenuReveal,
HeaderMenuTrigger,
} from "@/components/ui/header-menu";
</script>
<template>
<HeaderMenu>
<HeaderMenuTrigger>
<HeaderMenuBurger />
</HeaderMenuTrigger>
<HeaderMenuPanel>
<HeaderMenuClose />
<HeaderMenuReveal />
</HeaderMenuPanel>
<HeaderMenuPage>
<HeaderMenuPageContent />
</HeaderMenuPage>
</HeaderMenu>
</template>API Reference
HeaderMenu
| Prop | Type | Default | Description |
|---|---|---|---|
open | boolean | — | Whether the sheet is open. Supports v-model:open. |
side | "right" | "left" | "top" | "bottom" | "right" | Edge the sheet slides in from. A swipe toward that edge closes it. |
variant | "straight" | "floating" | "glass" | "full" | "underlay" | "straight" | straight is flush and plain, floating is an inset rounded card, glass is translucent and blurred, full takes the whole width. underlay keeps the panel in place and slides the page away from it at desktop width, and is a full width sheet below that. |
name | string | — | Share this menu's state under a name, so a HeaderMenuPage elsewhere in the layout, not an ancestor, can follow it. |
underlayWidth | string | "clamp(22rem, 33.333%, 30rem)" | Width of the underlay panel, any CSS length. A percentage is of the page. |
offset | string | "3.5rem" | Height of the header the sheet hangs under, any CSS length. The sheet and its backdrop start below it. |
portalTo | string | HTMLElement | — | Keep the sheet inside this element instead of the page. Use it for a menu shown in a frame. |
| Slot | Description |
|---|---|
default | The trigger and the panel. Renders no element of its own. |
HeaderMenuTrigger
| Prop | Type | Default | Description |
|---|---|---|---|
label | string | "Menu" | Accessible name of the button. |
text | string | — | A visible label next to the icon. |
barClass | string | — | Replaces the bar colour, bg-primary by default. |
HeaderMenuPanel
| Prop | Type | Default | Description |
|---|---|---|---|
title | string | "Menu" | Screen reader title. |
description | string | "Navigation menu" | Screen reader description. |
size | "sm" | "md" | "lg" | "xl" | "2xl" | "md" ("sm" when floating) | Widest the sheet gets on a screen wider than a phone. On a phone it always takes the whole width, and a sheet from the top or bottom does too. |
overlayClass | string | — | Classes for the backdrop, merged over its defaults. bg-black/80 for a darker one. |
bodyClass | string | — | Classes for the scrolling area that holds the content. |
HeaderMenuPage
| Prop | Type | Default | Description |
|---|---|---|---|
name | string | — | The HeaderMenu to follow when it is not an ancestor, for a page layer in a layout and a menu in the header. |
class | string | — | Wraps the header and the page content. With the underlay variant at desktop width it narrows from the right, rounds its corners and dims while the menu is open. |
HeaderMenuPageContent
| Prop | Type | Default | Description |
|---|---|---|---|
class | string | — | The part of the page that slides sideways by the width of the panel. Leave the header outside it so the logo stays put. It is inert while the menu is open. |
HeaderMenuReveal
| Prop | Type | Default | Description |
|---|---|---|---|
as | string | "div" | A line of the underlay panel. Each one slides in from the right and fades in a beat after the one before it. |
HeaderMenuClose
| Prop | Type | Default | Description |
|---|---|---|---|
text | string | "Close" | Label of the close button inside the panel. |
HeaderMenuBurger
| Prop | Type | Default | Description |
|---|---|---|---|
open | boolean | false | Morphs the two bars into a cross. |
Accessibility
Keyboard shortcuts and ARIA behavior.
| Shortcut | Description |
|---|---|
| Enter + Space | Open or close the sheet from the button. |
| Tab | Move through the sheet; focus stays inside while it is open. |
| Esc | Close the sheet and return focus to the button. |
- Built on the Drawer, so the sheet follows the finger, closes on a swipe toward its edge and on the back button.
- The button keeps pointer events while the page is locked, so it can close the sheet it opened.
- Motion is replaced by instant changes under prefers-reduced-motion.