FairGarden Design

Navigation Menu

The desktop site navigation on Base UI's Navigation Menu: caps bar items whose triggers open dropdown, overview or index panels under the bar. Inside a Navigation Bar it runs from --ds-nav-inline-n-above (1024 px by default); below it the drawer takes over.

import {
  NavigationMenu,
  NavigationMenuItem,
  NavigationMenuTrigger,
  NavigationMenuContent,
  NavigationMenuLink,
} from '@fairgarden-private/design/components/NavigationMenu'

Triggers are buttons. They open on click, Enter, Space or ArrowDown, and on mouse hover intent: 150 ms (--ds-delay-nav-open) to open and 300 ms (--ds-delay-nav-close) to close after the pointer leaves, both fed to Base UI from the one NAV_DELAY_MS constant. Once a panel is open, the next trigger switches instantly, and the safe pointer path keeps a diagonal move into a panel from switching it. Focus alone never opens a panel. Opening from the keyboard moves focus to the panel's first link, and Escape closes it and returns focus to the trigger. Only the open trigger reads aria-expanded="true", and closed panels are unmounted.

Pass currentPath, or let the Navigation Bar pass it. A link whose path equals it is current (aria-current="page": the --ds-stroke-3 bar and weight 700 in the bar, a weight and underline in a panel). A bar item whose section (for a trigger) or href is a path prefix of it is the parent of current (aria-current="true", a --border-size-2 bar). Hover is an accent underline under the label, and open is the --ds-stroke-3 bar flush with the rule, so hover, open and current never look alike.

From the navigation data. NavigationMenuSections builds the items from the shared navigation data (SitemapSections from @fairgarden-private/design/utils/navigation), the same object that feeds the drawer's sections and the footer's sitemap, so the footer mirrors the panels (see the Footer's navigation demo). A section with a description, a promo or third-tier links opens an overview panel, panel: 'index' an index panel, and a flat section a dropdown that starts with its landing page; a section with only an href is a plain bar link.

Overview panels

Overview panels

kind="overview" (LTA) is full-bleed under the bar, with its content on the 12-column grid of --ds-container-content. featured takes the section's landing page, a serif link with a › and a one-line description, then a hairline tier rule. The children are caps link groups, 2-up in columns 1–8 beside the optional promo card (one Tab stop), or up to 4-up without it. search adds one Search field; the panel stays open while it has focus. A plain NavigationMenuContent is the dropdown list of 3–8 links. A panel taller than the viewport scrolls in a Scroll Area.

NavigationMenuOverview.tsx
'use client'

import * as React from 'react'
import { Search } from '@fairgarden-private/design/components/Search'
import {
  NavigationMenu,
  NavigationMenuContent,
  NavigationMenuFeatured,
  NavigationMenuGroup,
  NavigationMenuItem,
  NavigationMenuLink,
  NavigationMenuPromo,
  NavigationMenuTrigger,
} from '@fairgarden-private/design/components/NavigationMenu'
import { photo } from './photo'
import styles from './overview.module.css'

/**
 * Three LTA-style overview panels and one dropdown. The page sits in
 * What We Do › Our Programs, so What We Do shows the parent-of-current bar
 * and Our Programs is current inside its panel.
 */
export function NavigationMenuOverview() {
  return (
    <div className={styles.frame}>
      <NavigationMenu currentPath="/what-we-do/our-programs" className={styles.bar}>
        <NavigationMenuItem>
          <NavigationMenuTrigger section="/why-land-matters">Why Land Matters</NavigationMenuTrigger>
          <NavigationMenuContent
            kind="overview"
            featured={
              <NavigationMenuFeatured
                href="/why-land-matters"
                description="How saving land safeguards our future."
              >
                Why Land Matters
              </NavigationMenuFeatured>
            }
            promo={
              <NavigationMenuPromo
                href="/why-land-matters/land-is-the-answer"
                title="Land Is the Answer"
                image={<img src={photo} alt="A ridge of protected forest above a river valley" />}
              >
                Protected land cleans our water, cools our towns and feeds our families.
              </NavigationMenuPromo>
            }
          >
            <NavigationMenuGroup heading="Land Conservation" href="/why-land-matters/land-conservation">
              <NavigationMenuLink href="/why-land-matters/land-conservation/why-conserve">
                Why conserve land
              </NavigationMenuLink>
              <NavigationMenuLink href="/why-land-matters/land-conservation/easements">
                Conservation easements
              </NavigationMenuLink>
              <NavigationMenuLink href="/why-land-matters/land-conservation/land-trusts">
                What a land trust does
              </NavigationMenuLink>
              <NavigationMenuLink href="/why-land-matters/land-conservation/stewardship">
                Caring for land forever
              </NavigationMenuLink>
            </NavigationMenuGroup>
            <NavigationMenuGroup heading="Conservation Priorities" href="/why-land-matters/priorities">
              <NavigationMenuLink href="/why-land-matters/priorities/climate">Climate</NavigationMenuLink>
              <NavigationMenuLink href="/why-land-matters/priorities/water">Clean water</NavigationMenuLink>
              <NavigationMenuLink href="/why-land-matters/priorities/farms">Farms and food</NavigationMenuLink>
              <NavigationMenuLink href="/why-land-matters/priorities/wildlife">Wildlife habitat</NavigationMenuLink>
              <NavigationMenuLink href="/why-land-matters/priorities/communities">
                Community-centered conservation
              </NavigationMenuLink>
            </NavigationMenuGroup>
          </NavigationMenuContent>
        </NavigationMenuItem>

        <NavigationMenuItem>
          <NavigationMenuTrigger section="/what-we-do">What We Do</NavigationMenuTrigger>
          <NavigationMenuContent
            kind="overview"
            featured={
              <NavigationMenuFeatured
                href="/what-we-do"
                description="We help permanently protect the land that you need and love."
              >
                What We Do
              </NavigationMenuFeatured>
            }
            promo={
              <NavigationMenuPromo
                href="/what-we-do/gaining-ground"
                title="Together, Let's Keep Gaining Ground"
                image={<img src={photo} alt="Volunteers planting along a creek" />}
              >
                See how land trusts are protecting more land, in every state, every year.
              </NavigationMenuPromo>
            }
          >
            <NavigationMenuGroup heading="Our Programs" href="/what-we-do/our-programs">
              <NavigationMenuLink href="/what-we-do/our-programs/accreditation">Accreditation</NavigationMenuLink>
              <NavigationMenuLink href="/what-we-do/our-programs/conservation-defense">
                Conservation defense
              </NavigationMenuLink>
              <NavigationMenuLink href="/what-we-do/our-programs/policy">Policy and advocacy</NavigationMenuLink>
              <NavigationMenuLink href="/what-we-do/our-programs/grants">Grants</NavigationMenuLink>
              <NavigationMenuLink href="/what-we-do/our-programs/training">Training and events</NavigationMenuLink>
            </NavigationMenuGroup>
            <NavigationMenuGroup heading="Our Collective Impact" href="/what-we-do/impact">
              <NavigationMenuLink href="/what-we-do/impact/census">National land trust census</NavigationMenuLink>
              <NavigationMenuLink href="/what-we-do/impact/stories">Success stories</NavigationMenuLink>
              <NavigationMenuLink href="/what-we-do/impact/annual-report">Annual report</NavigationMenuLink>
            </NavigationMenuGroup>
          </NavigationMenuContent>
        </NavigationMenuItem>

        <NavigationMenuItem>
          <NavigationMenuTrigger section="/take-action">Take Action</NavigationMenuTrigger>
          <NavigationMenuContent
            kind="overview"
            featured={
              <NavigationMenuFeatured href="/take-action" description="How you can make an impact.">
                Take Action
              </NavigationMenuFeatured>
            }
            search={<Search label="Find a land trust near you" placeholder="Search by name or town…" />}
            promo={
              <NavigationMenuPromo
                href="/take-action/give/stewards"
                title="Join Stewards of the Land"
                image={<img src={photo} alt="A farmer walking a hayfield at dusk" />}
              >
                Monthly gifts keep conserved land cared for, season after season.
              </NavigationMenuPromo>
            }
          >
            <NavigationMenuGroup heading="Get Involved" href="/take-action/get-involved">
              <NavigationMenuLink href="/take-action/get-involved/volunteer">Volunteer</NavigationMenuLink>
              <NavigationMenuLink href="/take-action/get-involved/events">Find an event</NavigationMenuLink>
              <NavigationMenuLink href="/take-action/get-involved/story">Share your story</NavigationMenuLink>
            </NavigationMenuGroup>
            <NavigationMenuGroup heading="Conserve Your Land" href="/take-action/conserve">
              <NavigationMenuLink href="/take-action/conserve/options">Conservation options</NavigationMenuLink>
              <NavigationMenuLink href="/take-action/conserve/tax">Tax benefits</NavigationMenuLink>
              <NavigationMenuLink href="/take-action/conserve/talk">Talk to a land trust</NavigationMenuLink>
            </NavigationMenuGroup>
            <NavigationMenuGroup heading="Give" href="/take-action/give">
              <NavigationMenuLink href="/take-action/give/donate">Donate</NavigationMenuLink>
              <NavigationMenuLink href="/take-action/give/monthly">Give monthly</NavigationMenuLink>
              <NavigationMenuLink href="/take-action/give/legacy">Leave a legacy</NavigationMenuLink>
            </NavigationMenuGroup>
            <NavigationMenuGroup heading="Partner" href="/take-action/partner">
              <NavigationMenuLink href="/take-action/partner/business">Business partnerships</NavigationMenuLink>
            </NavigationMenuGroup>
          </NavigationMenuContent>
        </NavigationMenuItem>

        <NavigationMenuItem>
          <NavigationMenuTrigger section="/about">About</NavigationMenuTrigger>
          <NavigationMenuContent>
            <NavigationMenuLink href="/about/story">Our story</NavigationMenuLink>
            <NavigationMenuLink href="/about/staff">Staff and board</NavigationMenuLink>
            <NavigationMenuLink href="/about/careers">Careers</NavigationMenuLink>
            <NavigationMenuLink href="/about/contact">Contact</NavigationMenuLink>
          </NavigationMenuContent>
        </NavigationMenuItem>
      </NavigationMenu>
    </div>
  )
}

Index panels

Index panels

kind="index" (Audubon) is a nested vertical menu: NavigationMenuCategory rows (a --size-px-13 column at a 44 px pitch) beside the selected category's link pane, with a featuredBar across both. One category is always selected: the one holding the current page, else the first. It is marked by a --ds-stroke-3 start-edge bar and weight 700. Categories switch on click, Enter or mouse rest. The panel attaches at its trigger's start edge, end-aligns inside the content container, and takes square top and --ds-radius-8 bottom corners.

NavigationMenuIndex.tsx
'use client'

import * as React from 'react'
import {
  NavigationMenu,
  NavigationMenuCategory,
  NavigationMenuContent,
  NavigationMenuFeaturedBar,
  NavigationMenuItem,
  NavigationMenuLink,
  NavigationMenuTrigger,
} from '@fairgarden-private/design/components/NavigationMenu'
import styles from './index-panel.module.css'

/**
 * Audubon-style index panels: a category list beside the selected
 * category's links, with a featured bar across both. The page is an owl
 * species page, so Explore Birds is the parent of current and Bird Guide
 * opens selected.
 */
export function NavigationMenuIndex() {
  return (
    <div className={styles.frame}>
      <NavigationMenu currentPath="/explore/bird-guide/great-horned-owl" className={styles.bar}>
        <NavigationMenuItem>
          <NavigationMenuTrigger section="/our-work">Our Work</NavigationMenuTrigger>
          <NavigationMenuContent
            kind="index"
            featuredBar={
              <NavigationMenuFeaturedBar href="/our-work">See All of Our Work</NavigationMenuFeaturedBar>
            }
          >
            <NavigationMenuCategory label="Conservation">
              <NavigationMenuLink href="/our-work/conservation/grasslands">Grasslands</NavigationMenuLink>
              <NavigationMenuLink href="/our-work/conservation/coasts">Coasts and shorelines</NavigationMenuLink>
              <NavigationMenuLink href="/our-work/conservation/forests">Working forests</NavigationMenuLink>
              <NavigationMenuLink href="/our-work/conservation/water">Water in the West</NavigationMenuLink>
            </NavigationMenuCategory>
            <NavigationMenuCategory label="Climate">
              <NavigationMenuLink href="/our-work/climate/report">Survival by degrees</NavigationMenuLink>
              <NavigationMenuLink href="/our-work/climate/solutions">Natural climate solutions</NavigationMenuLink>
              <NavigationMenuLink href="/our-work/climate/energy">Clean energy siting</NavigationMenuLink>
            </NavigationMenuCategory>
            <NavigationMenuCategory label="Community Science">
              <NavigationMenuLink href="/our-work/science/count">Winter bird count</NavigationMenuLink>
              <NavigationMenuLink href="/our-work/science/watch">Climate watch</NavigationMenuLink>
              <NavigationMenuLink href="/our-work/science/data">Open data</NavigationMenuLink>
            </NavigationMenuCategory>
          </NavigationMenuContent>
        </NavigationMenuItem>

        <NavigationMenuItem>
          <NavigationMenuTrigger section="/explore">Explore Birds</NavigationMenuTrigger>
          <NavigationMenuContent
            kind="index"
            featuredBar={
              <NavigationMenuFeaturedBar href="/explore/near-you">
                Search for Birds in Your Area
              </NavigationMenuFeaturedBar>
            }
          >
            <NavigationMenuCategory label="Birds Near You">
              <NavigationMenuLink href="/explore/near-you/map">Bird map</NavigationMenuLink>
              <NavigationMenuLink href="/explore/near-you/walks">Guided walks</NavigationMenuLink>
              <NavigationMenuLink href="/explore/near-you/centers">Nature centers</NavigationMenuLink>
            </NavigationMenuCategory>
            <NavigationMenuCategory label="Bird Guide">
              <NavigationMenuLink href="/explore/bird-guide/owls">Owls</NavigationMenuLink>
              <NavigationMenuLink href="/explore/bird-guide/great-horned-owl">Great horned owl</NavigationMenuLink>
              <NavigationMenuLink href="/explore/bird-guide/warblers">Warblers</NavigationMenuLink>
              <NavigationMenuLink href="/explore/bird-guide/shorebirds">Shorebirds</NavigationMenuLink>
            </NavigationMenuCategory>
            <NavigationMenuCategory label="Bird-Friendly Living">
              <NavigationMenuLink href="/explore/living/plants">Native plants</NavigationMenuLink>
              <NavigationMenuLink href="/explore/living/windows">Safer windows</NavigationMenuLink>
              <NavigationMenuLink href="/explore/living/feeders">Feeders and baths</NavigationMenuLink>
            </NavigationMenuCategory>
            <NavigationMenuCategory label="Photography">
              <NavigationMenuLink href="/explore/photo/awards">Photo awards</NavigationMenuLink>
              <NavigationMenuLink href="/explore/photo/ethics">Ethical bird photography</NavigationMenuLink>
            </NavigationMenuCategory>
          </NavigationMenuContent>
        </NavigationMenuItem>

        <NavigationMenuItem>
          <NavigationMenuTrigger section="/get-involved">Get Involved</NavigationMenuTrigger>
          <NavigationMenuContent>
            <NavigationMenuLink href="/get-involved/volunteer">Volunteer</NavigationMenuLink>
            <NavigationMenuLink href="/get-involved/chapters">Find a chapter</NavigationMenuLink>
            <NavigationMenuLink href="/get-involved/advocate">Advocate</NavigationMenuLink>
          </NavigationMenuContent>
        </NavigationMenuItem>

        <NavigationMenuItem>
          <NavigationMenuLink href="/news">News</NavigationMenuLink>
        </NavigationMenuItem>
      </NavigationMenu>
    </div>
  )
}

API Reference

The desktop site navigation [D182]: a nav labelled “Main” holding the bar’s items. Triggers are buttons that open their panel on click, Enter, Space or ArrowDown, and on hover intent under a mouse (--ds-delay-nav-open, closing --ds-delay-nav-close after the pointer leaves); focus alone never opens one. Opening from the keyboard moves focus to the panel’s first link; Escape closes and returns focus to the trigger. Panels attach at 0 offset under the bar’s bottom rule, switch instantly and scroll in a Scroll Area when taller than the viewport.

PropTypeDescription
label
string | undefined

The landmark’s name. Default “Main”.

currentPath
string | undefined

The current page’s URL path. A link whose path equals it is current (aria-current="page"); a bar item whose section is a path prefix of it is the parent of current (aria-current="true"). Inside a Navigation Bar it defaults to the bar’s currentPath.

primary
| 'ruby'
| 'olive'
| 'sage'
| 'slate'
| 'sand'
| 'gray'
| 'mauve'
| 'brown'
| 'bronze'
| 'gold'
| 'red'
| 'crimson'
| 'tomato'
| 'pink'
| 'plum'
| 'indigo'
| 'iris'
| 'violet'
| 'purple'
| null
| undefined

Primary Radix scale for the bar’s parts: labels, bars and focus ring. Never defaulted; omitted, it inherits the scope [D133]. The panels keep the white preset’s scales.

secondary
| 'ruby'
| 'olive'
| 'sage'
| 'slate'
| 'sand'
| 'gray'
| 'mauve'
| 'brown'
| 'bronze'
| 'gold'
| 'red'
| 'crimson'
| 'tomato'
| 'pink'
| 'plum'
| 'indigo'
| 'iris'
| 'violet'
| 'purple'
| 'amber'
| 'blue'
| 'cyan'
| 'grass'
| 'green'
| 'jade'
| 'lime'
| 'mint'
| 'orange'
| 'sky'
| 'teal'
| 'yellow'
| null
| undefined

Secondary Radix scale for the bar’s parts: the chevrons and the hover underline (--role-glyph, --role-accent). Never defaulted.

children
React.ReactNode | undefined

NavigationMenuItems, in bar order.

One bar item: a NavigationMenuTrigger with its NavigationMenuContent, or a plain NavigationMenuLink. value identifies it when the menu is controlled; omitted, one is generated.

A bar trigger: a button with a caps label (type-label, [D165]) and the expand_more chevron in --role-glyph, which flips while open. It opens its panel on click, Enter, Space, ArrowDown or mouse hover intent, never on focus alone; the section’s landing page is the panel’s first link.

PropTypeDescription
section
string | undefined

The path of the section this trigger opens (/what-we-do). While the page lies in it, the trigger is the parent of current (aria-current="true", the --border-size-2 bar) [D182].

A link. In the bar it is a caps item with no rest underline; in a panel it is a type-body-ui row at a --ds-size-hit pitch in Link’s list-link build (kind="nav" with list), whose hover is --role-link-hover only (§9.3) [D181]. active defaults to “its path is the current page” (aria-current="page"); a bar link whose path is a prefix of the page is the parent of current. Panel links close the panel on click.

A panel. It renders in the menu’s portaled white overlay scope, attached under the bar’s bottom rule: overview full-bleed with its content on the 12-column grid of --ds-container-content; index and dropdown at the trigger’s start edge, end-aligned to the content container, with square top and --ds-radius-8 bottom corners.

PropTypeDescription
featured
React.ReactNode | undefined
featuredBar
React.ReactNode | undefined
kind
'dropdown' | 'overview' | 'index' | undefined

dropdown (default): a simple list panel of 3–8 NavigationMenuLinks.

promo
React.ReactNode | undefined
search
React.ReactNode | undefined
children
React.ReactNode | undefined

Overview parts: NavigationMenuFeatured, NavigationMenuGroup and NavigationMenuPromo

The overview link (featured): the trigger’s own section landing page, a type-itemhead serif link in --role-heading with a trailing › in --role-accent, then its description. Put it in featured.

PropTypeDescription
description
React.ReactNode | undefined

One line of type-body-ui in --role-muted under the link.

A caps link group in an overview panel: a heading (a link with › when href is given) over its links at a --ds-size-hit pitch.

PropTypeDescription
heading
React.ReactNode | undefined

The group heading, set in type-label caps.

href
string | undefined

Makes the heading a link with a trailing ›, to the group’s landing page.

children
React.ReactNode | undefined

The group’s NavigationMenuLinks.

The optional promo card of an overview panel (≤ 1 per panel): a §12.2 card with a 16:9 image, a stretched title link (one Tab stop) and a blurb. Its hover is the title link’s --role-link-hover; no shadow.

PropTypeDescription
href
string

The destination: the card’s one Tab stop, its stretched title link.

image
React.ReactNode | undefined

A 16:9 image (an img with its alt).

title
React.ReactNode

The title, type-itemhead.

children
React.ReactNode | undefined

A two-line type-body-ui blurb.

className
string | undefined

Class names for the card, added after its own.

Index parts: NavigationMenuCategory and NavigationMenuFeaturedBar

One category of an index panel: a row in the category list (a trigger of the nested vertical menu) and its links in the pane. The selected category takes a --ds-stroke-3 start-edge bar and --font-weight-7.

PropTypeDescription
label
React.ReactNode

The category row’s label.

value
string | undefined

Identifies the category; omitted, the panel assigns one.

children
React.ReactNode | undefined

The category’s NavigationMenuLinks, shown in the link pane.

className
string | undefined

Class names for the category row, added after its own.

The featured bar of an index panel: one type-itemhead link with a › in --role-glyph, across both panes above a --role-hairline rule. Put it in featuredBar.

Additional types

NAV_DELAY_MS
navigationMenu
NavigationMenuCategoryProps
navigationMenuContent
NavigationMenuContentKind
NavigationMenuContentProps
NavigationMenuFeaturedBarProps
NavigationMenuFeaturedProps
NavigationMenuFrame
NavigationMenuFrameContext
NavigationMenuGroupProps
NavigationMenuItemProps
NavigationMenuLinkProps
NavigationMenuPromoProps
NavigationMenuProps
NavigationMenuSectionsProps
NavigationMenuTriggerProps

Specification: DESIGN-SYSTEM.md §9.6 (navigation menu) [D181, D182], with the overlay panels of §9.1 and the fit budget of §11.5 [D183].