Westy Design Systemv0.2.7
OverviewComponentsExamplesStorybook

Foundations

  • Typography
  • Colors
  • Spacing
  • Radius
  • Shadows
  • Icons

Components

  • Accordion
  • Alert
  • Alert Dialog
  • Aspect Ratio
  • Avatar
  • Badge
  • Breadcrumb
  • Button
  • Button Group
  • Calendar
  • Card
  • Carousel
  • Chart
  • Checkbox
  • Collapsible
  • Combobox
  • Command
  • Context Menu
  • Data Table
  • Date Picker
  • Dialog
  • Direction
  • Drawer
  • Dropdown Menu
  • Empty
  • Field
  • Hover Card
  • Input
  • Input Group
  • Input OTP
  • Item
  • Kbd
  • Label
  • Menubar
  • Native Select
  • Navigation Menu
  • Pagination
  • Popover
  • Progress
  • Questionnaire
  • Radio Group
  • Resizable
  • Scroll Area
  • Select
  • Separator
  • Sheet
  • Sidebar
  • Skeleton
  • Slider
  • Sonner
  • Spinner
  • Switch
  • Table
  • Tabs
  • Textarea
  • Toggle
  • Toggle Group
  • Tooltip

Chat

  • Attachment
  • Bubble
  • Marker
  • Message
  • Message Scroller

Components

Navigation Menu

A collection of links for navigating websites.

Playground

  • Docs
—viewport
—children
—data-active
—dir
Usage
Each NavigationMenuItem pairs a NavigationMenuTrigger with its expandable NavigationMenuContent full of NavigationMenuLinks. Menus open on hover or focus, and by default every content panel renders inside one shared viewport that resizes and slides between items. Links compose framework links via asChild and stack a title over a description with a column wrapper inside the link.
import Link from "next/link"
import {
  NavigationMenu,
  NavigationMenuContent,
  NavigationMenuItem,
  NavigationMenuLink,
  NavigationMenuList,
  NavigationMenuTrigger,
} from "@workspace/ui/components/navigation-menu"

<NavigationMenu>
  <NavigationMenuList>
    <NavigationMenuItem>
      <NavigationMenuTrigger>Getting started</NavigationMenuTrigger>
      <NavigationMenuContent>
        <ul className="grid w-72 gap-1">
          <li>
            <NavigationMenuLink asChild>
              <Link href="/docs">
                <div className="flex flex-col gap-1 text-sm">
                  <div className="leading-none font-medium">Introduction</div>
                  <div className="line-clamp-2 text-muted-foreground">
                    What the design system is and how it fits Westy.
                  </div>
                </div>
              </Link>
            </NavigationMenuLink>
          </li>
        </ul>
      </NavigationMenuContent>
    </NavigationMenuItem>
  </NavigationMenuList>
</NavigationMenu>
Links
An item can hold a plain NavigationMenuLink with no dropdown — pass navigationMenuTriggerStyle() so it matches the triggers. To render a framework link, compose with asChild. Mark the current page with data-active for the muted highlight; the active prop additionally exposes aria-current="page".
  • Docs
  • Components
  • Blocks
import Link from "next/link"
import {
  NavigationMenuLink,
  navigationMenuTriggerStyle,
} from "@workspace/ui/components/navigation-menu"

<NavigationMenuItem>
  <NavigationMenuLink
    asChild
    active={pathname === "/docs"}
    data-active={pathname === "/docs" || undefined}
    className={navigationMenuTriggerStyle()}
  >
    <Link href="/docs">Docs</Link>
  </NavigationMenuLink>
</NavigationMenuItem>
Without viewport
Pass viewport={false} to drop the shared viewport: each content panel becomes its own popover positioned under its trigger instead of sliding inside one centered surface. Use it when triggers sit far apart and the centered viewport would detach the panel from the trigger that opened it.
<NavigationMenu viewport={false}>
  <NavigationMenuList>
    <NavigationMenuItem>
      <NavigationMenuTrigger>Products</NavigationMenuTrigger>
      <NavigationMenuContent>
        <ul className="grid w-64 gap-1">
          <li>
            <NavigationMenuLink href="#">Components</NavigationMenuLink>
          </li>
          <li>
            <NavigationMenuLink href="#">Charts</NavigationMenuLink>
          </li>
        </ul>
      </NavigationMenuContent>
    </NavigationMenuItem>
  </NavigationMenuList>
</NavigationMenu>
With icons
Links accept an icon before the label — svgs are sized to 16px automatically. Keep the icon inside the title row when the link also carries a description.
import { RocketLaunchIcon } from "@phosphor-icons/react"

<NavigationMenuContent>
  <ul className="grid w-72 gap-1">
    <li>
      <NavigationMenuLink asChild>
        <Link href="/docs">
          <div className="flex flex-col gap-1 text-sm">
            <div className="flex items-center gap-2 leading-none font-medium">
              <RocketLaunchIcon />
              Getting started
            </div>
            <div className="line-clamp-2 text-muted-foreground">
              Install the package and render your first component.
            </div>
          </div>
        </Link>
      </NavigationMenuLink>
    </li>
  </ul>
</NavigationMenuContent>
RTL
Radix reads direction from the dir prop (or a surrounding Direction provider) — a plain dir="rtl" ancestor is not enough for the keyboard navigation and slide animations to flip. Styling follows via logical properties: the trigger caret keeps its position with ms-1, and the viewport anchors to the start edge.
  • الوثائق
<NavigationMenu dir="rtl">
  <NavigationMenuList>
    <NavigationMenuItem>
      <NavigationMenuTrigger>البدء</NavigationMenuTrigger>
      <NavigationMenuContent>
        <ul className="grid w-72 gap-1">
          <li>
            <NavigationMenuLink href="#">مقدمة</NavigationMenuLink>
          </li>
          <li>
            <NavigationMenuLink href="#">التثبيت</NavigationMenuLink>
          </li>
        </ul>
      </NavigationMenuContent>
    </NavigationMenuItem>
    <NavigationMenuItem>
      <NavigationMenuLink href="#" className={navigationMenuTriggerStyle()}>
        الوثائق
      </NavigationMenuLink>
    </NavigationMenuItem>
  </NavigationMenuList>
</NavigationMenu>
Accessibility
Site navigation, not a menu: the root renders a <nav> landmark with a list, and content holds plain links — so it deliberately avoids the ARIA menu roles, which are reserved for application menus. Triggers are buttons exposing aria-expanded and aria-controls; menus open on hover, focus, Enter or Space, arrow keys move within the bar and panels, and Escape closes and returns focus to the trigger. An active link exposes aria-current="page".
<nav aria-label="Main" data-orientation="horizontal">
  <ul>
    <li>
      <button aria-expanded="true" aria-controls="radix-:r1:">Products</button>
      <div id="radix-:r1:">                  <!-- content panel -->
        <a href="/components">Components</a>
      </div>
    </li>
    <li>
      <a href="/docs" aria-current="page">Docs</a>
    </li>
  </ul>
</nav>
API Reference
Every part wraps the matching Radix Navigation Menu primitive and accepts all of its props. The notable ones and the local additions:
ComponentPropDefault
NavigationMenuviewport?: booleantrue
NavigationMenudir?: "ltr" | "rtl"inherited
NavigationMenudelayDuration?: number200
NavigationMenuskipDelayDuration?: number300
NavigationMenuvalue?: string, onValueChange?: (value: string) => void—
NavigationMenuItemvalue?: string—
NavigationMenuLinkactive?: booleanfalse
NavigationMenuLinkasChild?: booleanfalse
NavigationMenuLinkonSelect?: (event: Event) => void—
<NavigationMenu data-slot="navigation-menu" />            // <nav>, renders the viewport
<NavigationMenuList data-slot="navigation-menu-list" />   // <ul>
<NavigationMenuItem data-slot="navigation-menu-item" />   // <li>
<NavigationMenuTrigger data-slot="navigation-menu-trigger" />  // <button aria-expanded> + caret
<NavigationMenuContent data-slot="navigation-menu-content" />  // panel inside the viewport
<NavigationMenuLink data-slot="navigation-menu-link" />   // <a>
<NavigationMenuIndicator data-slot="navigation-menu-indicator" />  // arrow under the trigger
<NavigationMenuViewport data-slot="navigation-menu-viewport" />    // shared popover surface

navigationMenuTriggerStyle()  // cva helper — trigger look for plain links

Tokens used

11 design tokens consumed by the Navigation Menu component.

  • --popover

    Popover

    bg-popover
  • --popover-foreground

    Popover Foreground

    text-popover-foreground
  • --muted

    Muted

    hover:bg-mutedfocus:bg-muteddata-open:bg-muted/50data-[active=true]:bg-muted/50
  • --ring

    Ring

    focus-visible:ring-ring/50
  • --foreground

    Foreground

    ring-foreground/10
  • --border

    Border

    bg-border
  • --radius-lg

    Radius 1× (10px)

    rounded-lg
  • --radius-md

    Radius 0.8× (8px)

    rounded-md
  • --radius-sm

    Radius 0.6× (6px)

    rounded-sm
  • --text-sm

    Text Small (14px)

    text-sm
  • --spacing

    Spacing unit (4px)

    h-9px-4py-2p-2gap-1.5mt-1.5size-3size-4