Component
Navigation Menu

Navigation Menu

A collection of links for navigating websites.

Installation

Install the following dependencies

npm i @radix-ui/react-navigation-menu

Copy and paste the following code into your project

components/ui/navigation-menu/index.tsx
'use client'
 
import * as React from 'react'
import * as NavigationMenuPrimitive from '@radix-ui/react-navigation-menu'
import { ChevronDown } from 'lucide-react'
import { createStyleContext } from '@shadow-panda/style-context'
import { styled } from '@shadow-panda/styled-system/jsx'
import { cx } from '@shadow-panda/styled-system/css'
import { navigationMenu } from '@shadow-panda/styled-system/recipes'
 
const { withProvider, withContext } = createStyleContext(navigationMenu)
 
const BaseNavigationMenu = React.forwardRef<
  React.ElementRef<typeof NavigationMenuPrimitive.Root>,
  React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Root>
>(({ children, ...props }, ref) => (
  <NavigationMenuPrimitive.Root ref={ref} {...props}>
    {children}
    <NavigationMenuViewport />
  </NavigationMenuPrimitive.Root>
))
BaseNavigationMenu.displayName = NavigationMenuPrimitive.Root.displayName
 
const BaseNavigationMenuTrigger = React.forwardRef<
  React.ElementRef<typeof NavigationMenuPrimitive.Trigger>,
  React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Trigger>
>(({ children, ...props }, ref) => (
  <NavigationMenuPrimitive.Trigger ref={ref} {...props}>
    {children} <ChevronDown aria-hidden="true" />
  </NavigationMenuPrimitive.Trigger>
))
BaseNavigationMenuTrigger.displayName = NavigationMenuPrimitive.Trigger.displayName
 
const ViewportWrapper = withContext(styled('div'), 'viewportWrapper')
 
const BaseNavigationMenuViewport = React.forwardRef<
  React.ElementRef<typeof NavigationMenuPrimitive.Viewport>,
  React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Viewport>
>(({ className, ...props }, ref) => (
  <ViewportWrapper>
    <NavigationMenuPrimitive.Viewport className={cx(className)} ref={ref} {...props} />
  </ViewportWrapper>
))
BaseNavigationMenuViewport.displayName = NavigationMenuPrimitive.Viewport.displayName
 
export const NavigationMenu = withProvider(styled(BaseNavigationMenu), 'root')
export const NavigationMenuList = withContext(styled(NavigationMenuPrimitive.List), 'list')
export const NavigationMenuItem = withContext(styled(NavigationMenuPrimitive.Item), 'item')
export const NavigationMenuTrigger = withContext(styled(BaseNavigationMenuTrigger), 'trigger')
export const NavigationMenuContent = withContext(styled(NavigationMenuPrimitive.Content), 'content')
export const NavigationMenuLink = withContext(styled(NavigationMenuPrimitive.Link), 'link')
export const NavigationMenuViewport = withContext(styled(BaseNavigationMenuViewport), 'viewport')
export const NavigationMenuIndicator = withContext(
  styled(NavigationMenuPrimitive.Indicator),
  'indicator',
  { children: <div /> },
)

Update the import paths to match your project setup

Usage

import {
  NavigationMenu,
  NavigationMenuContent,
  NavigationMenuIndicator,
  NavigationMenuItem,
  NavigationMenuLink,
  NavigationMenuList,
  NavigationMenuTrigger,
  NavigationMenuViewport,
} from '@/components/ui/navigation-menu'
<NavigationMenu>
  <NavigationMenuList>
    <NavigationMenuItem>
      <NavigationMenuTrigger>Item One</NavigationMenuTrigger>
      <NavigationMenuContent>
        <NavigationMenuLink>Link</NavigationMenuLink>
      </NavigationMenuContent>
    </NavigationMenuItem>
  </NavigationMenuList>
</NavigationMenu>

Examples

When using the Next.js <Link /> component, you can use the asChild prop from the <NavigationMenuLink /> component to render it as the link.

<NavigationMenuItem>
  <NavigationMenuLink asChild>
    <Link href="/docs">Documentation</Link>
  </NavigationMenuLink>
</NavigationMenuItem>