Navigation Menu
Top-level navigation primitive with trigger/content panels.
npx shadcn@latest add @aavya/ui-navigation-menu
One-time setup — add the @aavya registry to your components.json so branded dependencies resolve to Aavya (not stock shadcn):
"registries": { "@aavya": "https://registry-dev.aavya.com/r/{name}.json" }Or install by full URL: npx shadcn@latest add https://registry-dev.aavya.com/r/ui-navigation-menu.json
| Prop | Type | Default |
|---|---|---|
| viewport? | boolean | true |
NavigationMenu forwards remaining props to NavigationMenuPrimitive.Root props.
Do
- Use it for top-level site navigation, with optional single-level dropdown sections.
- Keep labels short and parallel; group related destinations under one trigger.
- Mark the current page so users know where they are.
Don’t
- Don't use it for in-page actions or a command menu — use a Dropdown Menu.
- Don't build deep, multi-level trees; keep to one dropdown level.
- Don't hide primary destinations behind hover-only triggers on touch devices.
Role
Navigation region with menu semantics (handled by Radix).
Keyboard
Tab moves between top-level items; arrow keys move within an open section; Esc closes it. (handled)
Screen reader
Announced as a navigation landmark; triggers announce expanded/collapsed. Give the nav an aria-label when there's more than one on the page — you provide this.
Focus
Focus returns to the trigger when a section closes. (handled)
Gotcha
Links must be real anchors — render items asChild wrapping a Link so browser and AT navigation work.
import { NavigationMenu } from '@/components/ui/navigation-menu'
export default function Example() {
return (
<div className="p-6">
<NavigationMenu />
</div>
)
}
import * as React from 'react'
import * as NavigationMenuPrimitive from '@radix-ui/react-navigation-menu'
import { cva } from 'class-variance-authority'
import { ChevronDownIcon } from 'lucide-react'
import { cn } from '@/lib/utils'
function NavigationMenu({
className,
children,
viewport = true,
...props
}: React.ComponentProps<typeof NavigationMenuPrimitive.Root> & {
viewport?: boolean
}) {
return (
<NavigationMenuPrimitive.Root
data-slot='navigation-menu'
data-viewport={viewport}
className={cn('group/navigation-menu relative flex max-w-max flex-1 items-center justify-center', className)}
{...props}
>
{children}
{viewport && <NavigationMenuViewport />}
</NavigationMenuPrimitive.Root>
)
}
function NavigationMenuList({ className, ...props }: React.ComponentProps<typeof NavigationMenuPrimitive.List>) {
return (
<NavigationMenuPrimitive.List
data-slot='navigation-menu-list'
className={cn('group flex flex-1 list-none items-center justify-center gap-1', className)}
{...props}
/>
)
}
function NavigationMenuItem({ className, ...props }: React.ComponentProps<typeof NavigationMenuPrimitive.Item>) {
return (
<NavigationMenuPrimitive.Item data-slot='navigation-menu-item' className={cn('relative', className)} {...props} />
)
}
const navigationMenuTriggerStyle = cva(
'group bg-backgro