Navigation

Navigation Menu
v1.0.5
Documentation Under Review

A collection of links for navigating internal applications with accessible multi-level dropdown support and customizable styling.

The Navigation Menu component provides an accessible, keyboard-navigable menu system built on Radix UI Navigation Menu primitives. It supports multi-level dropdowns, smooth animations, active page tracking, and custom theming for internal product applications.

Installation

Install the Navigation Menu component from the Catalyst component library:

npm install @pmi/catalyst-navigation-menu

Anatomy

The Navigation Menu is a compound component system with 9 primitives:

import {
  NavigationMenuRoot,
  NavigationMenuList,
  NavigationMenuItem,
  NavigationMenuTrigger,
  NavigationMenuContent,
  NavigationMenuLink,
  NavigationMenuSub,
  NavigationMenuViewport,
  NavigationMenuIndicator,
} from '@pmi/catalyst-navigation-menu'

<NavigationMenuRoot>
  <NavigationMenuList>
    <NavigationMenuItem>
      <NavigationMenuLink href="/">Dashboard</NavigationMenuLink>
    </NavigationMenuItem>
    <NavigationMenuItem>
      <NavigationMenuTrigger>Settings</NavigationMenuTrigger>
      <NavigationMenuContent>
        {/* Dropdown content */}
      </NavigationMenuContent>
    </NavigationMenuItem>
    <NavigationMenuIndicator />
  </NavigationMenuList>
  <NavigationMenuViewport />
</NavigationMenuRoot>

Examples

Default

A complete navigation menu with certification cards and dropdown content:

Preview

Default Opened

Navigation menu with the first dropdown pre-opened, featuring a certification card:

Preview

Disabled

All navigation triggers are disabled, preventing interaction:

Preview

Custom Styles

Apply custom aqua theme colors for product applications, featuring certification cards with the custom styling:

Preview

Advanced Examples

API Reference

The root container for the navigation menu system.

Prop

Type

Data Attributes:

  • data-orientation - "horizontal" | "vertical"

Contains all menu items in a horizontal or vertical list.

Prop

Type

A single navigation menu item that can contain a link or trigger.

Prop

Type

The button that toggles the dropdown content.

Prop

Type

Data Attributes:

  • data-state - "open" | "closed"
  • data-disabled - Present when disabled
  • data-active - Present when the trigger is active

The component that contains the content shown in the dropdown.

Prop

Type

Data Attributes:

  • data-state - "open" | "closed"
  • data-motion - "from-start" | "from-end" | "to-start" | "to-end"

A navigational link that can be used standalone or inside dropdown content.

Prop

Type

Data Attributes:

  • data-active - Present when the link is active

The viewport that contains the dropdown content with smooth animations.

Prop

Type

Data Attributes:

  • data-state - "open" | "closed"

CSS Variables:

  • --radix-navigation-menu-viewport-width - The width of the viewport
  • --radix-navigation-menu-viewport-height - The height of the viewport

An optional arrow indicator that highlights the active item.

Prop

Type

Data Attributes:

  • data-state - "visible" | "hidden"
  • data-orientation - "horizontal" | "vertical"

Used to create sub-navigation within dropdown content.

Prop

Type

Animations

The Navigation Menu includes smooth animations powered by Tailwind CSS:

Content Animations

  • Enter from right/left: Content slides in from the side (250ms)
  • Exit to right/left: Content slides out to the side (250ms)

Viewport Animations

  • Scale in: Viewport scales in with a 3D rotation effect (200ms)
  • Scale out: Viewport scales out smoothly (200ms)

Indicator Animations

  • Fade in/out: Arrow indicator fades in and out (200ms)

All animations respect the prefers-reduced-motion media query for accessibility.

Accessibility

WCAG 2.1 Compliance

The Navigation Menu component meets WCAG 2.1 Level AA standards:

  • ✅ Keyboard Navigation: Full support for Arrow keys, Tab, Enter, and Escape
  • ✅ Focus Management: Visible focus indicators and proper focus trapping
  • ✅ Screen Reader Support: Proper ARIA attributes and announcements
  • ✅ Active Page Indicators: Uses aria-current="page" for the current page
  • ✅ Color Contrast: Meets 4.5:1 minimum contrast ratio
  • ✅ Reduced Motion: Respects prefers-reduced-motion preference

Keyboard Shortcuts

KeyAction
TabMove focus to next interactive element
Shift + TabMove focus to previous interactive element
Arrow DownOpen dropdown or move focus to next item
Arrow UpMove focus to previous item
Arrow RightMove focus to next trigger
Arrow LeftMove focus to previous trigger
Enter or SpaceActivate focused trigger or link
EscapeClose open dropdown

Best Practices

  1. Always provide aria-label on NavigationMenuRoot to describe the navigation
  2. Use aria-current="page" to indicate the current page
  3. Add descriptive text for icon-only triggers using aria-label
  4. Ensure sufficient contrast for hover and active states (especially with custom colors)
  5. Test with keyboard to ensure all items are reachable
  6. Test with screen readers (NVDA, JAWS, VoiceOver)

Performance Considerations

Optimizing navigation menu performance ensures fast page loads and smooth interactions:

Code Splitting

Navigation menu content can be lazy-loaded using React's dynamic imports:

import dynamic from 'next/dynamic'

const NavigationMenuContent = dynamic(() => 
  import('@pmi/catalyst-navigation-menu').then(mod => mod.NavigationMenuContent),
  { ssr: true }
)

Image Optimization

Use Next.js Image component for course and certification card images to optimize loading:

import Image from 'next/image'

const CourseCard = ({ image, title }) => (
  <div className="aspect-video w-full overflow-hidden">
    <Image 
      src={image} 
      alt={title}
      width={400}
      height={225}
      loading="lazy"
      className="h-full w-full object-cover"
    />
  </div>
)

Hover Delay Optimization

Use the delayDuration prop to optimize hover behavior for large menus:

<NavigationMenuRoot 
  delayDuration={300}  // Slightly longer delay reduces unnecessary opens
  skipDelayDuration={200}  // Faster transitions between menus
>
  {/* menu content */}
</NavigationMenuRoot>

Data Memoization

Use useMemo for large menu data structures to prevent unnecessary re-renders:

const categories = useMemo(() => [
  { id: 'certifications', name: 'Certifications', /* ... */ },
  { id: 'courses', name: 'All Courses', /* ... */ },
  { id: 'learning-paths', name: 'Learning Paths', /* ... */ }
], []) // Empty deps array - data doesn't change

Bundle Size

  • Component Bundle: ~8KB gzipped (including Radix UI primitives)
  • With Icons: ~12KB gzipped (when using 5-10 icons)
  • Tree Shaking: Import only the components you need

Best Practices

  • Avoid rendering large lists (>50 items) in a single dropdown - use search/filtering instead
  • Defer loading non-critical menu content until user interaction
  • Use CSS transforms for animations (already implemented) for better performance
  • Monitor menu opening time - should be <100ms for good UX
  • Consider using a service worker to cache navigation menu data

Design Tokens

The component uses the following Catalyst design tokens:

Colors (Default)

  • pmi-off-black-800 - Text and outline colors
  • pmi-off-black-50 - Hover background (light mode)
  • pmi-violet-700 - Hover background (dark mode)
  • white - Text and background colors

Colors (Custom - Aqua Theme)

  • neutral-800 - Text and background colors
  • pmi-aqua-50 - Hover background (light mode)
  • pmi-aqua-800 - Hover background (dark mode)
  • pmi-aqua-500 - Focus ring color

Spacing

  • h-8 (32px) - Height for triggers and links
  • h-10 (40px) - Height for the list container
  • px-3 (12px) - Horizontal padding for items
  • p-6 (24px) - Padding for dropdown content

Typography

  • font-aeonik - Font family
  • text-base (16px) - Base text size
  • font-medium (500) - Font weight
  • leading-6 (24px) - Line height

Border Radius

  • rounded-lg (8px) - Item and list border radius
  • rounded-xl (12px) - Link item border radius

On this page