Skip to content
WingoUI
ComponentsTemplatesDocsPricingAI agentsBlogChangelogContact
Components
Buttons & Actions
ButtonButton GroupCopy ButtonDelete ButtonTheme ToggleToggleToggle Group
Inputs
Avatar UploadCalendarCheckboxColor PickerComboboxCountry SelectCron PickerCurrency InputDate PickerDate Range PickerDate Time PickerDuration PickerEmail InputEmoji PickerFile UploadFilter BuilderInputInput GroupListboxMasked InputMention InputMonth PickerMulti SelectNumber InputOTP InputPassword InputPhone InputRadio GroupRatingSearch InputSegmented ControlSelectSignature PadSliderSwitchTag InputTextareaTime PickerTimezone SelectTree Select
Forms
Address InputBooking WidgetCSV ImportFieldForm WizardInline EditInvoice line itemsRich Text EditorSchema Builder
Navigation
Back To TopBounce SidebarBreadcrumbCommand MenuGlobal SearchGooey NavHook SidebarNav MenuNav TabsPaginationProximity SidebarScroll ProgressSidebarStepsTable Of ContentsTabsTopbarUser MenuWorkspace Switcher
Overlays
Alert DialogContext MenuDialogDrawerDropdown MenuFamily DrawerHover CardPopoverShare DialogSheetShortcuts DialogTooltipTour
Feedback
AlertBannerCookie ConsentEmoji ReactionEmpty StateNotification BellNotification CenterProgressRoute ProgressSetup ChecklistSkeletonSpinnerToast
Data Display
Approval FlowAvatarBadgeCalendar ViewCode BlockComment ThreadContact cardCountdownDescription ListDiff ViewerFile ListFile managerFolderGanttJSON ViewerKbdLog ViewerMarkdownPresenceSchedulerTagTimelineTree View
Tables & Lists
Audit LogData TableDeal PipelineEditable GridKanbanListMembers tablePermissions MatrixTableTask ListVirtual List
Charts & Stats
Animated CounterArea chartBar chartDonut chartFunnel chartGaugeGitHub ActivityHeatmap calendarLeaderboardLine chartRadar chartRadial barSparklineStat CardTrackerTrend badge
Layout
AccordionApp ShellCardCollapsibleDetail LayoutEntity HeaderPage HeaderScroll AreaSeparatorSettings LayoutSplit ViewToolbar
Media
Audio PlayerCarouselCSV ViewerDOCX EditorDOCX ViewerExcel ViewerFile SystemImage compareImage CropperImage GalleryImage LightboxLocation MapPDF ViewerPowerPoint ViewerQR CodeStep PlayerVideo Player
AI Kit
Agent Status CardChat MessageChat ThreadChat WidgetConversation ListFluid OrbGrid RevealMatrix OrbModel PickerPrompt InputReasoning IndicatorRule BuilderSuggestion ChipsTool Call TimelineUsage MeterVoice InputWorkflow Canvas
Text & Effects
Background PatternGravity LettersMarqueeTerminalText AnimateText Rotate
Mobile
Action SheetBottom Tab BarFABHaptic ButtonHero HeaderInstall PromptLarge Title HeaderNotification BannerOnboarding CarouselPicker WheelPull To RefreshSlide To ConfirmSticky CTA BarSwipe DeckSwipeable Tabs
Commerce
Cart drawerCategory pickerCheckout stepsCoupon inputFavorite buttonFilter panelListing cardListing gridOrder trackerPricePrice rangePricing tableProduct galleryQuantity stepperReviewsSeller card
Marketing Sections
App Download SectionBlog Cards SectionCTA SectionFAQ SectionFeature GridFeature ShowcaseHero SectionIntegrations SectionLogo CloudMarketing FooterMarketing HeaderMarketing SectionNewsletter SectionPricing SectionStats SectionSteps SectionTeam SectionTestimonials SectionTimeline SectionVideo Section
Blocks
Admin Dashboard PageAdmin ShellAI Chat PageAPI Keys PageAutomation Builder PageCheckout PageCRM Contact PageCRM Pipeline PageError PagesInbox PageInvoice PageKPI DashboardListing Detail PageLogin PageMarketplace Home PageMarketplace Search PageMarketplace ShellMobile App HomeOnboarding FlowOrder History PagePost Listing WizardPricing PageProfile PageRegister PageSettings PageUsers Admin Page
Templates
About PageAcademy PageAccessibility PageAffiliate PageAgency PageAI Product PageAppointment Booking PageBlog PageBlog Post PageBug Bounty PageCareers PageChangelog PageCommunity PageCompare PageContact PageCustomer Story PageCustomers PageDemo Booking PageDevelopers PageDocs Home PageDownload PageEnterprise PageEvents PageExperts PageFAQ PageFeature PageGlossary PageHelp Article PageHelp Center PageHome Services PageImpact PageIntegration Detail PageIntegrations PageJob Detail PageLanding PageLaunch PageLegal PageManifesto PagePortfolio PagePress PageProduct Tour PagePromo PageReal Estate PageReferral PageResearch Report PageRestaurant PageRoadmap PageROI Calculator PageSecurity PageSolutions PageStartups PageStatus PageStorefront PageSwitch PageTemplate Gallery PageTravel PageWaitlist PageYear in Review Page
Hooks & Utilities
AI ChatChart kitCommerceDate utilsFile exportFile typesFiltersForm validationHapticsInvoicingMotion presetsNavigationNumber formatRelative timeRomanian locationsSpreadsheetText matchTonesUIProvideruseClipboarduseConsentuseControllableStateuseCooldownuseDebounceuseKeyboardInsetuseLocaleuseLongPressuseMediaControlsuseMediaQueryuseOverflowItemsusePersistedStateuseScrollEdgesuseScrollStateuseSelectionuseShortcutuseStickToBottom
GalleryTheme

Navigation

Nav Menu

Navigation

Nav Menu React component for Tailwind CSS v4

Hook SidebarNav Tabs
Live props
State
defaultValue
currentPath
defaultMobileOpen
Appearance
viewport
indicator
size
Layout
align
mobileBreakpoint
Behavior
delayDuration150ms
skipDelayDuration300ms
modal
Code
import { NavMenu } from "@/components/ui/nav-menu"

<NavMenu />
  1. Home
  2. Components
  3. Navigation
  4. Nav Menu
Free

Nav Menu React component for Tailwind CSS v4

v1.0.1·Updated in 1.6.0

A React navigation menu for websites: links and dropdown panels, lists or mega menus with a featured card, morphing through one panel.

Point at a menu and after a short delay its panel drops in; slide to the next one and the same panel glides under it, resizes to the new content and swaps it with a short slide in the direction you moved. A soft pill (or an underline) follows the pointer between triggers and rests on the section you are in. Click a link and the panel closes while the active item updates. With the keyboard, Tab reaches every trigger and link, ArrowLeft / ArrowRight move between triggers, Enter or Space opens a panel and Tab moves into it, ArrowDown opens it and lands on its first link, arrows move between its links and Escape closes it and returns focus. When the bar is narrower than the breakpoint (a phone) a hamburger takes the list's place: tap it and a full-screen menu slides in from the right with one accordion section per menu, 48px rows, the actions stacked full width at the bottom, and the section you are in already open. Choosing a link, tapping the close button, swiping the menu right or Escape closes it. Under reduced motion panels fade without sliding and resize at once.

Nav Menu is a free React component in the React navigation components category, written in TypeScript for React 19 and Tailwind CSS v4. It installs as source with npx wingo-ui@latest add nav-menu, together with Accordion, Badge, Button, Sheet, useControllableState and 3 more and the npm packages @radix-ui/react-navigation-menu, motion and lucide-react.

Add to a project

Requirements: React 19 and Tailwind CSS v4, in Next.js (App Router or Pages), Vite or React Router. Installation guide · Next.js setup · Vite setup

npx wingo-ui@latest add nav-menu

Usage

Import NavMenu from @/components/ui/nav-menu.

import { Calculator, FileText, Receipt } from "lucide-react"
import { Button } from "@/components/ui/button"
import { NavMenu, type NavMenuItem } from "@/components/ui/nav-menu"
import { NavLink } from "@/lib/navigation"

const items: NavMenuItem[] = [
  {
    label: "Product",
    items: [
      { label: "Invoicing", href: "/billing", icon: <FileText />, description: "Invoices and estimates in 30 seconds" },
      { label: "E-invoicing", href: "/e-invoicing", icon: <Receipt />, description: "Sent and validated automatically" },
      { label: "Reports", href: "/reports", icon: <Calculator />, description: "Payments, sales tax and overdue" },
    ],
    featured: {
      title: "New: e-invoices sent automatically",
      description: "Every invoice reaches your client with zero extra clicks.",
      image: "/demo/laptop.jpg",
      href: "/news/e-invoicing",
    },
  },
  { label: "Pricing", href: "/pricing" },
  { label: "Contact", href: "/contact" },
]

export function SiteHeader() {
  return (
    <header className="sticky top-0 z-sticky border-b border-foreground/10 bg-background px-4 md:px-6">
      <NavMenu
        items={items}
        logo={<NavLink href="/" className="text-[15px] font-semibold">SimpleInvoice</NavLink>}
        actions={
          <>
            <Button variant="ghost" size="sm">Log in</Button>
            <Button size="sm">Try it free</Button>
          </>
        }
      />
    </header>
  )
}

Props

  • items*
    NavMenuItem[]

    Top-level entries, the shared NavItem shape (id, label, href, icon, description, badge, disabled, external, match, onSelect, items) plus content (replaces the generated panel), featured ({ title, description?, image?, href, badge? }: a 16:10 card next to the links, a compact row in the phone menu) and columns (1 | 2 | 3; default 2 above 4 links, else 1). An item with items (or content) becomes a dropdown whose panel lists them; with an href as well, the panel starts with a "View all" row to it. Otherwise it is a link.

  • value
    string

    The active item's key (navItemKey: id, else href, else the label), at any depth. Controls the active state.

  • defaultValuedefault ""
    string

    The active item's key (navItemKey: id, else href, else the label) while uncontrolled and no current path is known; clicks then move it. Empty: the first enabled item. Ignored under a router: the playground drops its pretend router's path while this is set. Try /pricing or Solutions.

  • onValueChange
    (key: string, item: NavItem) => void

    Fires on every link or row activation, in every mode (controlled, router, uncontrolled).

  • currentPathdefault ""
    string

    The current pathname. Empty: the LinkProvider's. With a path the router decides what is active (the longest matching href) and the top-level item above it gets the active look. Try /pricing or /product/reports.

  • logo
    ReactNode

    The start slot, usually a link home. Repeated in the phone menu's header.

  • actions
    ReactNode

    The end slot ("Log in", "Try it free"). In the phone menu the same buttons stack full width at 48px, the last one on top.

  • mobileActions
    ReactNode

    Replaces actions in the phone menu's footer.

  • viewportdefault true
    boolean

    One shared panel that follows the open trigger and morphs between menus (the Stripe header). Off: each panel opens as its own surface under its trigger.

  • indicatordefault "pill"
    "pill" | "underline" | "none"

    The highlight that slides between hovered and open triggers on a smooth spring and rests on the active section: a soft pill, a 2px underline, or nothing (color only).

  • sizedefault "md"
    "sm" | "md"

    Triggers 32 / 36px and the bar 56 / 64px. Triggers grow to 44px on touch screens.

  • aligndefault "center"
    "start" | "center" | "end"

    Where the list sits between logo and actions. center keeps it in the middle of the bar.

  • mobileBreakpointdefault "md"
    "md" | "lg"

    Below this width of the bar (768 / 1024px) the hamburger and the full-screen menu replace the list and actions, with CSS container queries, so the server HTML is already right. Use lg when the items do not fit a tablet.

  • delayDurationdefault 150
    number

    Milliseconds of hover before a panel opens, so a pointer passing over the bar does not flash menus.

  • skipDelayDurationdefault 300
    number

    Milliseconds after leaving a trigger during which the next one opens at once, without the delay.

  • defaultMobileOpendefault false
    boolean

    Starts with the phone menu open (uncontrolled).

  • mobileOpen
    boolean

    The phone menu's open state, controlled. Pair with onMobileOpenChange.

  • onMobileOpenChange
    (open: boolean) => void

    Fires when the phone menu opens or closes (hamburger, close button, a chosen link, swipe, Escape).

  • modaldefault true
    boolean

    The phone menu traps focus, locks the page scroll and dims the page. Turn it off for inline previews of the open menu.

  • container
    HTMLElement | null

    Where the phone menu portals to, e.g. a phone frame. Default: document.body.

  • linkComponent
    (props: LinkComponentProps) => ReactNode

    Renders every link through this component (a router Link) instead of the LinkProvider's.

  • labels
    { navigation?: string; openMenu?: string; closeMenu?: string; menu?: string; viewAll?: string }

    Every string: the nav's aria-label ("Main"), the hamburger ("Open menu" / "Close menu"), the phone menu's hidden title ("Menu") and the first row of a panel whose item has its own page ("View all").

  • classNames
    Partial<Record<"logo" | "list" | "item" | "trigger" | "link" | "chevron" | "indicator" | "viewport" | "content" | "panelLink" | "featured" | "actions" | "mobileTrigger" | "sheet" | "sheetLink" | "sheetActions", string>>

    Extra classes for the inner parts.

  • className
    string

    Extra classes for the bar (the <nav>), merged last.

Parts

  • NavMenuItem

    type

    One top-level entry: a NavItem (label, href, icon, description, badge, and items for the panel's links) plus content to replace the generated panel, featured for a highlighted card and columns (1, 2 or 3).

  • NavMenuFeatured

    type

    The card beside a panel's links: title, description, image (16:10), href and badge.

Examples

Panels under their triggers

viewport={false}: every menu opens its own panel under its trigger instead of one shared, morphing panel.

Underline indicator

indicator="underline" with the list at the start; the line follows the pointer and rests on Pricing.

Phone menu

Below the breakpoint the hamburger opens a full-screen menu: accordion sections, 48px rows, actions at the thumb.

App navigation

A compact two-level nav for an app (size="sm"); the router path /invoices marks Sales and its row active.

Over a dark hero photo

A transparent header on a photo: a dark scope turns the triggers white and the panel dark.

Dependencies

@radix-ui/react-navigation-menumotionlucide-reactaccordionbadgebuttonsheetuse-controllable-statemotionnavigationui-config

Files

  • components/ui/nav-menu.tsx

FAQ

Is the React Nav Menu component free?

Yes. The source is free and needs no account: copy it from the Code tab or install it with the CLI.

How do I install Nav Menu?

Run npx wingo-ui@latest add nav-menu. It also adds the Wingo UI items it builds on (Accordion, Badge, Button, Sheet, useControllableState and 3 more) and the npm packages @radix-ui/react-navigation-menu, motion and lucide-react. With shadcn, run npx shadcn@latest add https://wingo-ui.com/r/nav-menu.json.

See also

Marketing HeaderTopbarSheetAccordionNavigationlibGooey Nav

Used in

Marketing HeaderDocs Home Page

More React navigation components

SidebarBack To TopCommand MenuGlobal SearchNav TabsPagination
All 19 React navigation components

Articles using this component

  • Shadcn Navbar: Mega Menu, Mobile Menu, Sticky Header

    Build it: screens and apps · Nov 5, 2026 · 9 min read

PreviousHook SidebarNext Nav Tabs
SimpleInvoice
  • Pricing
  • Contact
E-invoicing included in every plan

Invoices in 30 seconds. Your accountant will love you.

Send invoices, get paid and see who owes you, without spreadsheets or paperwork.

Recent invoices

Sep 23, 2026

  • Acme Corp#2026-0412Paid$2,480.00
  • Northwind Logistics#2026-0411Sent$650.50
  • Greenleaf Pharmacy#2026-0409Overdue$180.00

/ · hover 150ms · skip 300ms