Skip to content
Pinky UI

navigation

Morph Menu

A compact trigger that expands into a spatially continuous menu surface.

  • navigation
  • menu
  • overlay
  • mobile

Live preview

Quick usage

usage
import { MorphMenu } from "@pinky-ui/experiences";

<MorphMenu items={items} label="Site navigation" />

Presets

Default

The restrained Pinky production default.

Default behaviour

Quiet

A flatter or lower-intensity treatment for dense pages.

disabled={true}

Install

Add @pinky-ui/experiences as a dependency, or use the CLI to copy this component's source directly into your project — no dependency to manage, fully editable.

shell
npm install @pinky-ui/experiences

Prefer to run the whole repository locally instead?

repository
git clone https://github.com/florash/Pinky-UI.git
cd Pinky-UI
npm install
npm run dev

Props

PropTypeDefaultDescription
itemsMorphMenuItem[]Semantic navigation destinations.
classNamestringStyles the outer composition without changing its behaviour.
disabledbooleanfalseUses the static, readable composition.

Accessibility

  • Escape closes the menu and focus is trapped while open.
  • Closing restores trigger focus and releases body scroll.

Performance

  • Reuses the existing shared-layout Morph primitive.
  • No pointer or scroll loop is mounted.

Reduced motion

Spatial or continuous movement is removed while content, selection and controls remain available.

When to use

  • Compact editorial and mobile navigation

When not to use

  • Links that should remain visible at all times

Skill

What it does

Morph Menu turns a compact trigger into a short navigation surface with the same object continuity as the trigger. It is Pinky’s canonical compact navigation pattern.

Interaction anatomy

  • Trigger: one labelled menu button.
  • State: closed, opening, open and closing.
  • Motion: the trigger surface expands into the menu instead of being replaced by a card.
  • Surface: a short ordered list of semantic links plus an explicit close action.
  • Feedback: focus enters the menu and returns to the trigger on close.

Good for

  • Mobile headers with a small destination set.
  • Sparse editorial or portfolio navigation.
  • A compact index where the expanded list needs a little more room.

Avoid for

  • Permanent desktop navigation or a long information architecture.
  • A native disclosure that already communicates the relationship clearly.
  • Mixing it with another modal or hiding heavy media behind the trigger.

Live example

Open the live menu above, move through its links with Tab, and close with Escape. The links remain real links; the morph is only the handoff.

Usage

tsx
<MorphMenu
  trigger="Index"
  items={sections.map((section) => ({
    id: section.id,
    label: section.label,
    href: section.href,
  }))}
 />

Tune

  • Keep the list short enough to scan without scrolling.
  • Use maxWidth for the reading width, not for visual drama.
  • Give each item a stable label and a useful optional description.
  • Keep the trigger surface and panel in the same material family.

Accessibility

  • Preserve semantic links, an accessible menu label and a visible close button.
  • Escape, focus trapping, focus restoration and body-scroll handling are part of the pattern.
  • Keyboard users must reach every destination without a pointer.
  • Touch users get the same explicit trigger and link targets.

Reduced motion

The menu opens and closes immediately while focus order, link semantics and the close path remain unchanged.

Open this skill on its own page