FairGarden Design

Navigation Bar

The site header on every page, as a header landmark. It holds a skip link first, the green brand strip, an optional utility row, then the bar: the logo as a home link, the Navigation Menu, icon Buttons, the one action and, below the inline threshold, the drawer's menu Button.

import {
  NavigationBar,
  NavigationBarUtility,
  NavigationBarUtilityLink,
} from '@fairgarden-private/design/components/NavigationBar'

The bar is an opaque kind="band" Ground: the page ground it sits in (paper, white or the page's one pastel), or preset="night" only directly over the night media hero. It is 56 px tall (64 px from --lg-n-above), with a full-bleed --role-rule bottom rule, and its content is capped at --ds-container-content. Panels attach under that rule. currentPath flows to the menu, the drawer and the utility links, which mark the current page and the parent of the current page by URL path.

The site header

From --ds-nav-inline-n-above (1024 px by default, a build-time custom media) the inline menu and the 36 px utility row show. Below it they are replaced by the drawer's menu Button, and the utility links move to the drawer footer. Items never wrap. At the threshold the logo, items, search, action and gaps must fit the content container (944 px at 1024 px). Overflow goes to the utility row, then to a final "More" item with a dropdown panel, never a hamburger. A site over budget sets the custom media to 1440 px. Below 360 px the action moves into the drawer.

Page content starts here.
NavigationBarHeader.tsx
'use client'

import * as React from 'react'
import { Button } from '@fairgarden-private/design/components/Button'
import {
  NavDrawer,
  NavDrawerFooter,
  NavDrawerGroup,
  NavDrawerLink,
} from '@fairgarden-private/design/components/NavDrawer'
import {
  NavigationBar,
  NavigationBarUtility,
  NavigationBarUtilityLink,
} from '@fairgarden-private/design/components/NavigationBar'
import {
  NavigationMenu,
  NavigationMenuContent,
  NavigationMenuFeatured,
  NavigationMenuGroup,
  NavigationMenuItem,
  NavigationMenuLink,
  NavigationMenuPromo,
  NavigationMenuTrigger,
} from '@fairgarden-private/design/components/NavigationMenu'
import { Search } from '@fairgarden-private/design/components/Search'
import { photo } from './photo'
import { Wordmark } from './Wordmark'
import styles from './header.module.css'

/**
 * The full header on a page in What We Do › Our Programs: skip link, brand
 * strip, utility row, logo, the inline menu from 1024 px, search, the one
 * action, and the drawer below 1024 px (narrow the window to see it).
 */
export function NavigationBarHeader() {
  return (
    <div className={styles.page}>
      <NavigationBar
        logo={<Wordmark />}
        logoLabel="FairGarden home"
        currentPath="/what-we-do/our-programs"
        skipHref="#header-demo-content"
        utility={
          <NavigationBarUtility>
            <NavigationBarUtilityLink href="/about">About</NavigationBarUtilityLink>
            <NavigationBarUtilityLink href="/jobs">Job Board</NavigationBarUtilityLink>
            <NavigationBarUtilityLink href="/newsroom">Newsroom</NavigationBarUtilityLink>
            <NavigationBarUtilityLink href="/blog">Blog</NavigationBarUtilityLink>
          </NavigationBarUtility>
        }
        search={<Search kind="trigger" label="Search FairGarden" />}
        action={
          <Button variant="solid" size="sm" nativeButton={false} render={<a href="/donate" />}>
            Donate
          </Button>
        }
        drawer={
          <NavDrawer
            footer={
              <NavDrawerFooter
                action={
                  <Button variant="solid" size="lg" nativeButton={false} render={<a href="/donate" />}>
                    Donate
                  </Button>
                }
              >
                <NavDrawerLink href="/about">About</NavDrawerLink>
                <NavDrawerLink href="/newsroom">Newsroom</NavDrawerLink>
                <NavDrawerLink href="/accessibility">Accessibility settings</NavDrawerLink>
              </NavDrawerFooter>
            }
          >
            <NavDrawerGroup label="Why Land Matters">
              <NavDrawerLink href="/why-land-matters">Why land matters</NavDrawerLink>
              <NavDrawerLink href="/why-land-matters/land-conservation">Land conservation</NavDrawerLink>
              <NavDrawerLink href="/why-land-matters/priorities">Conservation priorities</NavDrawerLink>
            </NavDrawerGroup>
            <NavDrawerGroup label="What We Do">
              <NavDrawerLink href="/what-we-do">What we do</NavDrawerLink>
              <NavDrawerLink href="/what-we-do/our-programs">Our programs</NavDrawerLink>
              <NavDrawerLink href="/what-we-do/impact">Our collective impact</NavDrawerLink>
            </NavDrawerGroup>
            <NavDrawerGroup label="Take Action">
              <NavDrawerLink href="/take-action">Take action</NavDrawerLink>
              <NavDrawerLink href="/take-action/get-involved">Get involved</NavDrawerLink>
              <NavDrawerLink href="/take-action/give">Give</NavDrawerLink>
            </NavDrawerGroup>
            <NavDrawerLink href="/find-a-land-trust">Find a Land Trust</NavDrawerLink>
          </NavDrawer>
        }
      >
        <NavigationMenu>
          <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>
              </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>
              </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>
              }
            >
              <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/policy">Policy and advocacy</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>
              </NavigationMenuGroup>
              <NavigationMenuGroup heading="Training" href="/what-we-do/training">
                <NavigationMenuLink href="/what-we-do/training/courses">Courses</NavigationMenuLink>
                <NavigationMenuLink href="/what-we-do/training/rally">National conference</NavigationMenuLink>
              </NavigationMenuGroup>
            </NavigationMenuContent>
          </NavigationMenuItem>

          <NavigationMenuItem>
            <NavigationMenuTrigger section="/take-action">Take Action</NavigationMenuTrigger>
            <NavigationMenuContent>
              <NavigationMenuLink href="/take-action/get-involved">Get involved</NavigationMenuLink>
              <NavigationMenuLink href="/take-action/conserve">Conserve your land</NavigationMenuLink>
              <NavigationMenuLink href="/take-action/give">Give</NavigationMenuLink>
            </NavigationMenuContent>
          </NavigationMenuItem>

          <NavigationMenuItem>
            <NavigationMenuLink href="/find-a-land-trust">Find a Land Trust</NavigationMenuLink>
          </NavigationMenuItem>
        </NavigationMenu>
      </NavigationBar>
      <div id="header-demo-content" className={styles.content} tabIndex={-1}>
        Page content starts here.
      </div>
    </div>
  )
}

Ruled, masthead and compact

Ruled, masthead and compact

ruled splits the items with vertical rules. masthead stacks a wordmark row over the caps nav row, ruled above and below. compact is the docked header at the same height: the utility row and brand drawing drop, and the triggers, search and action stay.

The header is static by default (dock="none"). dock="pinned" docks it after 50vh of scroll, and it stays until its own place scrolls back into view. dock="swap" works with the sticky section bar: pass a zero-height sentinelRef at the bar's in-flow position. Once it passes the viewport top, upward scroll brings the header back in place of the bar, and downward scroll restores the bar. Hide the bar while onDockChange reports true, so the two never stack. While docked, the header turns compact and takes the top edge on --layer-2, swapped in by a --ds-duration-quick clip cut that is instant under reduced motion.

NavigationBarVariants.tsx
'use client'

import * as React from 'react'
import { Button } from '@fairgarden-private/design/components/Button'
import { NavigationBar } from '@fairgarden-private/design/components/NavigationBar'
import {
  NavigationMenu,
  NavigationMenuItem,
  NavigationMenuLink,
} from '@fairgarden-private/design/components/NavigationMenu'
import { Wordmark } from '../header/Wordmark'
import styles from './variants.module.css'

const sections = [
  { href: '/why-land-matters', label: 'Why Land Matters' },
  { href: '/what-we-do', label: 'What We Do' },
  { href: '/take-action', label: 'Take Action' },
]

function Items() {
  return (
    <NavigationMenu>
      {sections.map((section) => (
        <NavigationMenuItem key={section.href}>
          <NavigationMenuLink href={section.href}>{section.label}</NavigationMenuLink>
        </NavigationMenuItem>
      ))}
    </NavigationMenu>
  )
}

const action = (
  <Button variant="solid" size="sm">
    Donate
  </Button>
)

/** The ruled cells, the stacked masthead and the compact (docked) header, on the tide page ground. */
export function NavigationBarVariants() {
  return (
    <div className={styles.stack}>
      <NavigationBar ruled preset="tide" logo={<Wordmark />} logoLabel="FairGarden home" currentPath="/take-action" action={action}>
        <Items />
      </NavigationBar>
      <NavigationBar masthead logo={<Wordmark />} logoLabel="FairGarden home" currentPath="/what-we-do/our-programs" action={action}>
        <Items />
      </NavigationBar>
      <NavigationBar compact logo={<Wordmark />} logoLabel="FairGarden home" action={action}>
        <Items />
      </NavigationBar>
    </div>
  )
}

API Reference

The site header: a skip link first, the green brand strip, an optional utility row, then the bar holding the logo (a home link), the Navigation Menu (from --ds-nav-inline-n-above), icon Buttons, the one action and, below the threshold, the drawer’s menu Button. It is opaque, ruled at the bottom in --role-rule, 56 px tall (64 px from --lg-n-above), and its items never wrap: overflow goes to the utility row, then a “More” item [D183]. It prints as the §7.8 masthead’s logo only.

PropTypeDescription
action
React.ReactNode | undefined

The one primary action: a solid Button at size="sm". Moves into the drawer below 360 px.

brandDrawing
React.ReactNode | undefined

An optional fine-line brand drawing (--ds-stroke-0–75) beside the logo; dropped when compact.

compact
boolean | null | undefined

true: the compact header, even undocked. The sticky observer sets it while docked. Default false.

currentPath
string | undefined

The current page’s URL path, shared with the menu, drawer and utility links.

dock
NavigationBarDock | undefined

How the header docks. Default none.

drawer
React.ReactNode | undefined

The NavDrawer (menu Button and sheet), shown below --ds-nav-inline-n-above.

logo
React.ReactNode | undefined

The logo: an ink logo in currentColor (an svg or img), 28 px tall, 36 px from --lg-n-above.

logoHref
string | undefined

The home link. Default “/".

logoLabel
string | undefined

The home link’s accessible name, e.g. “FairGarden home”.

masthead
boolean | null | undefined

true: the stacked masthead. Default false.

onDockChange
((docked: boolean) => void) | undefined

Called when the header docks (true) or returns to its place (false).

preset
BandPreset | undefined

The header preset: a page ground (paper, white or the page’s pastel), or night only directly over the night media hero. Omitted, the header takes the page ground it sits in.

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

Override the preset’s primary (a pairing §2 verifies). Never defaulted [D133].

ruled
boolean | null | undefined

true: vertical --border-size-1 rules between items. Default false.

search
React.ReactNode | undefined

Icon Buttons, e.g. <Search kind="trigger" />, --size-px-1 apart.

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

Override the preset’s secondary. Never defaulted.

sentinelRef
React.RefObject<Element | null> | undefined

With dock="swap": a zero-height element at the section bar’s in-flow position.

skipHref
string | undefined

The skip link’s target. Default “#main”.

skipLabel
string | undefined

The skip link’s words. Default “Skip to main content”.

utility
React.ReactNode | undefined

A NavigationBarUtility row above the bar, from --ds-nav-inline-n-above; never docks.

children
React.ReactNode | undefined

The NavigationMenu, inline from --ds-nav-inline-n-above.

The 36 px utility row above the bar (§11.3): secondary destinations as text links in a nav labelled “Utility”, divided from the bar by a --role-hairline rule, aligned to --ds-container-content. Shown from --ds-nav-inline-n-above (below it, repeat its links in the drawer footer); the compact docked header drops it [D183]. Put it in the bar’s utility slot.

PropTypeDescription
label
string | undefined

The landmark’s name. Default “Utility”.

locale
React.ReactNode | undefined

An optional locale link at the end (“English ▾ Change language”); a control never sits here.

start
React.ReactNode | undefined

An optional start slot: a phone number or tagline, in --primary12.

children
React.ReactNode | undefined

The row’s NavigationBarUtilityLinks: text links only.

A utility link: type-label caps, no rest underline, the bare-text underline on hover [D181], a 24 px target at a 24 px pitch (the §1.5.12 utility exemption). The current page (its path equals the bar’s currentPath) takes aria-current="page" and the --ds-stroke-3 bar.

Additional types

navigationBar
NavigationBarContext
NavigationBarContextValue
NavigationBarDock
NavigationBarProps
NavigationBarUtilityLinkProps
NavigationBarUtilityProps

Specification: DESIGN-SYSTEM.md §11.5 (navigation bar) [D182, D183] and §11.3 (brand strip and utility bar); print per §7.8 (the masthead).