Motion Navigation Menu

A spring-animated navigation menu with a single morphing container, layout-animated active pill, and direction-aware content transitions.

Installation

File Structure

highlight.tsx
motion-navigation-menu.tsx

Usage

import {
  MotionNavigationMenu,
  MotionNavigationMenuContent,
  MotionNavigationMenuIndicator,
  MotionNavigationMenuItem,
  MotionNavigationMenuLink,
  MotionNavigationMenuList,
  MotionNavigationMenuTrigger,
} from "@/components/unlumen-ui/motion-navigation-menu";

const listHighlightClassName = "bg-primary/10 rounded-lg";
const contentHighlightClassName =
  "bg-primary/10 rounded-lg ring-1 ring-primary/15";

export default function Example() {
  return (
    <MotionNavigationMenu
      viewportClassName="bg-surface border-none shadow-none"
      springStiffness={350}
      springDamping={32}
    >
      <MotionNavigationMenuList highlightClassName={listHighlightClassName}>
        <MotionNavigationMenuItem value="products">
          <MotionNavigationMenuTrigger>Products</MotionNavigationMenuTrigger>
          <MotionNavigationMenuContent
            highlightClassName={contentHighlightClassName}
          >
            <div className="grid w-[400px] grid-cols-2 gap-1">
              <MotionNavigationMenuLink href="/analytics">
                <span className="text-sm font-medium">Analytics</span>
                <span className="text-muted-foreground text-xs">
                  Understand your data flow.
                </span>
              </MotionNavigationMenuLink>
              <MotionNavigationMenuLink href="/automation">
                <span className="text-sm font-medium">Automation</span>
                <span className="text-muted-foreground text-xs">
                  Streamline workflows.
                </span>
              </MotionNavigationMenuLink>
            </div>
          </MotionNavigationMenuContent>
        </MotionNavigationMenuItem>

        <MotionNavigationMenuIndicator />

        <MotionNavigationMenuItem>
          <MotionNavigationMenuLink
            href="/pricing"
            className="px-4 py-2 text-sm font-medium"
          >
            Pricing
          </MotionNavigationMenuLink>
        </MotionNavigationMenuItem>
      </MotionNavigationMenuList>
    </MotionNavigationMenu>
  );
}

API Reference

MotionNavigationMenu

PropTypeDefaultDescription
viewport?booleantrueWhen true, renders content inside the shared morphing viewport. When false, each content panel renders absolutely below its item.
viewportClassName?string-Additional classes applied to the morphing viewport.
springBounce?number0Bounce used by the spring transition for the viewport and content animations.
springStiffness?number350Stiffness used by the spring transition for the viewport and content animations.
springDamping?number32Damping used by the spring transition for the viewport and content animations.
value?string-Controlled active item value. Use an empty string to close the menu.
onValueChange?(value: string) => void-Callback fired when the active item value changes.
className?string-Additional classes applied to the root element.

MotionNavigationMenuList

PropTypeDefaultDescription
className?string-Additional classes applied to the list element.
highlightClassName?string-Additional classes applied to the hover highlight rendered behind trigger items.

MotionNavigationMenuItem

PropTypeDefaultDescription
value?string-Unique identifier for this item. Required when the item has a Trigger + Content pair.
className?string-Additional classes applied to the list item.

MotionNavigationMenuTrigger

PropTypeDefaultDescription
className?string-Additional classes applied to the trigger button.
children?React.ReactNode-Trigger content.

MotionNavigationMenuContent

Renders the panel shown when the parent item's trigger is active. Must be placed inside a MotionNavigationMenuItem that has a value prop. The content is portal-rendered into the morphing container, so its width drives the container's resize animation.

PropTypeDefaultDescription
className?string-Additional classes applied to the content wrapper.
highlightClassName?string-Additional classes applied to the hover highlight rendered behind links inside the content.
innerClassName?string-Additional classes applied to the inner content container.

MotionNavigationMenuLink

PropTypeDefaultDescription
href?string-Destination URL for the anchor.
className?string-Additional classes applied to the link.
children?React.ReactNode-Link content.

MotionNavigationMenuIndicator

PropTypeDefaultDescription
className?string-Additional classes applied to the indicator wrapper.

Notes

  • Shared viewport: with viewport enabled, open content is rendered inside one morphing viewport that animates width, height, opacity, and scale.
  • Direction-aware transitions: switching between menus slides content horizontally based on whether the new item is to the left or right of the previous one.
  • Custom highlights: use MotionNavigationMenuList's highlightClassName for trigger hover styling and MotionNavigationMenuContent's highlightClassName for dropdown link hover styling.
  • Controlled mode: pass value and onValueChange to control the active item from outside the component.
  • Overflow clamping: the dropdown automatically stays within its nearest clipping ancestor — no configuration needed when the menu is inside a constrained container like a preview panel or modal.

Credits

Built by Léo.

Keep in mind

Most components on this site are inspired by or recreated from existing work across the web. I'm not here to take credit; just to learn, experiment, and sometimes push things a bit further. If something looks familiar and I forgot to mention you, reach out and I'll fix that right away.