Navigation

Fullscreen Menu

A Nike-style fullscreen overlay menu — the backdrop unveils from the top down and the menu items slide up from under a mask in a staggered cascade.

This is a WebberUI Pro component

The install command below needs a licence to run; without one it returns 401.

How to install Pro components →See the plans →

Bring this into your project

Run this command in your project folder. The CLI adds the source and dependencies; then follow the usage example below.

npx webberui@latest add "https://webberui.com/r/fullscreen-menu.en.json?t=<install token>"

New project or installation trouble? Start here →

Playground

Tune the props live — the code snippet updates as you go, so you can dial in the look you want before copying it.

Active edited usageDefault props
<FullscreenMenu/>

The complete example includes the preview layout and data. Install the component first, then paste this file into your project.

Installation

npx webberui@latest add "https://webberui.com/r/fullscreen-menu.en.json?t=<install token>"

Or, once registries are configured in components.json, install it as @webberui/fullscreen-menu.

Usage

import {
  FullscreenMenu,
  FullscreenMenuTrigger,
  FullscreenMenuContent,
  FullscreenMenuItem,
} from "@/components/ui/fullscreen-menu";

<FullscreenMenu>
  <FullscreenMenuTrigger>Open menu</FullscreenMenuTrigger>

  <FullscreenMenuContent>
    <FullscreenMenuItem href="#men" index="01">
      Men
    </FullscreenMenuItem>
    <FullscreenMenuItem href="#women" index="02">
      Women
    </FullscreenMenuItem>
    <FullscreenMenuItem href="#sport" index="03">
      Sport collection
    </FullscreenMenuItem>
  </FullscreenMenuContent>
</FullscreenMenu>;

Clicking the trigger unveils the backdrop downward from the top of the screen, and then each FullscreenMenuItem slides up from under the mask in turn. Clicking the backdrop, pressing the close button in the top-right corner, or pressing Esc all close it; selecting an item closes it automatically by default.

FullscreenMenuItem renders as an <a> when it has an href and a <button> otherwise, and it can be paired with onSelect to handle selection:

<FullscreenMenuItem onSelect={() => router.push("/men")} index="01">
  Men
</FullscreenMenuItem>;

Passing open and onOpenChange switches it to controlled mode (for example so an external hamburger button can drive it):

const [open, setOpen] = React.useState(false);

<FullscreenMenu open={open} onOpenChange={setOpen}>
  {/* ... */}
</FullscreenMenu>;

Props

FullscreenMenu

PropTypeDefaultDescription
childrenReact.ReactNode—The content, which must include FullscreenMenuTrigger and FullscreenMenuContent
openboolean—Open state in controlled mode; when omitted, the component manages it internally
onOpenChange(open: boolean) => void—Callback fired when the open state changes (in both controlled and uncontrolled modes)

FullscreenMenuTrigger

PropTypeDefaultDescription
childrenReact.ReactNode—Trigger content
classNamestring—Appended to the trigger's className

FullscreenMenuContent

PropTypeDefaultDescription
childrenReact.ReactNode—Overlay content, usually several FullscreenMenuItem elements
align"start" | "center""start"Horizontal alignment of the menu items
labelstring"Main menu"Accessible label for the overlay (applied to role="dialog")
classNamestring—Appended to the overlay container's className

FullscreenMenuItem

PropTypeDefaultDescription
childrenReact.ReactNode—Item text
hrefstring—When set, renders as an <a>; otherwise a <button>
indexstring—Optional number label (such as "01"), shown before the item
onSelect() => void—Callback fired when the item is clicked and selected
closeOnSelectbooleantrueWhether selecting closes the menu automatically
classNamestring—Appended to the item link's className

FullscreenMenuClose

PropTypeDefaultDescription
childrenReact.ReactNodelucide-react X iconCustom button content
classNamestring—Appended to the close button's className

How it works

  • A staggered reveal: the list container uses staggerChildren to offset each item's trigger time, and every item sits inside a static overflow-hidden mask while only the inner link does the y displacement — so the text appears to "rise" from the edge of the mask, giving the clean Nike-style cropped edge. On exit, staggerDirection: -1 collapses them in reverse.
  • A top-down backdrop: the backdrop unveils downward from the top of the screen with scaleY (transformOrigin: top), and on exit it waits a moment before retracting, so the items leave first and the backdrop closes last.
  • Portaled to body: the overlay and the backdrop are rendered into document.body via createPortal, which avoids an ancestor's overflow clipping them or a transform creating a containing block that would break fixed positioning.
  • Layered pointer-events: the dialog layer is pointer-events-none by default so clicks outside the overlay land on the backdrop (which closes it), and only interactive elements such as links and the close button restore pointer-events on themselves.
  • controlled mode: passing open switches it to controlled and the component stops changing its internal state; onOpenChange fires in both controlled and uncontrolled modes, so you can keep it in sync with external navigation state.
  • Tuning points: hover and icon transition durations read var(--wb-duration-fast, 200ms) and the easing reads var(--wb-ease-out, cubic-bezier(0.22,1,0.36,1)), falling back to the defaults when undefined.

Accessibility

  • The overlay carries role="dialog", aria-modal="true", and an aria-label; focus moves into the overlay when it opens (tabIndex={-1}), and after closing focus returns to the trigger
  • The trigger is a native <button> carrying aria-haspopup="dialog" and the aria-expanded state, linked to the overlay with aria-controls while open
  • The menu is carried by a semantic <nav> with <ul>/<li> structure, and items render as <a> or <button> depending on href, all focusable and operable by keyboard
  • Pressing Esc or clicking the backdrop closes it; while open, body is set to overflow: hidden to lock background scrolling, and the original value is restored on close
  • When the user has "reduce motion" enabled at the system level, the backdrop and the items degrade to a quick fade in and out with no sense of displacement
  • The component takes the lightweight route and has no built-in focus trap; if the overlay contains many interactive elements and needs a complete keyboard focus cycle, pair it with a focus trap solution of your own