Skip to main contentSkip to docs navigation

Build tab, segment, and underline navigation with Nav, NavItem, and NavLink, or from a data array, with sizes, alignment, stacking, and fill layouts.

Overview

<Nav> shares its base markup and styling — the .nav class, active and disabled states — across plain, tabbed, segmented, and underlined navigation. Swap the variant prop to switch between styles without changing the surrounding markup.

Basic usage

<Nav> is built with flexbox and provides the foundation every style variant below builds on: some style overrides for working with lists, link padding for larger hit areas, and disabled styling. Compose it from <NavItem>/<NavLink> pairs, mark the current link with active, and mark an unavailable one with disabled.

JSX
import { Nav, NavItem, NavLink } from '@chassis-ui/react'

export const Example = () => {
  return (
    <Nav>
      <NavItem>
        <NavLink href="#" active>
          Active
        </NavLink>
      </NavItem>
      <NavItem>
        <NavLink href="#">Link</NavLink>
      </NavItem>
      <NavItem>
        <NavLink href="#">Link</NavLink>
      </NavItem>
      <NavItem>
        <NavLink href="#" disabled>
          Disabled
        </NavLink>
      </NavItem>
    </Nav>
  )
}

The <NavItem>/<NavLink> pairing is optional. Since .nav uses display: flex, rendering <Nav component="nav"> with direct <NavLink> children behaves the same way, without the extra markup.

JSX
import { Nav, NavLink } from '@chassis-ui/react'

export const Example = () => {
  return (
    <Nav component="nav">
      <NavLink href="#" active>
        Active
      </NavLink>
      <NavLink href="#">Link</NavLink>
      <NavLink href="#">Link</NavLink>
      <NavLink href="#" disabled>
        Disabled
      </NavLink>
    </Nav>
  )
}

Data-driven usage

Pass an items array to <Nav> to render navigation from data instead of composing children. Each item accepts label, href, active, and disabled.

JSX
import { Nav } from '@chassis-ui/react'

export const Example = () => {
  return (
    <Nav
      items={[
        { label: 'Home', href: '#', active: true },
        { label: 'Features', href: '#' },
        { label: 'Pricing', href: '#' },
        { label: 'Disabled', href: '#', disabled: true }
      ]}
    />
  )
}

The same items array works with the tabs and segments variants below.

JSX
import { Nav } from '@chassis-ui/react'

export const Example = () => {
  return (
    <Nav
      variant="tabs"
      items={[
        { label: 'Active', href: '#', active: true },
        { label: 'Link', href: '#' },
        { label: 'Another Link', href: '#' },
        { label: 'Disabled', href: '#', disabled: true }
      ]}
    />
  )
}
JSX
import { Nav } from '@chassis-ui/react'

export const Example = () => {
  return (
    <Nav
      variant="segments"
      items={[
        { label: 'Active', href: '#', active: true },
        { label: 'Link', href: '#' },
        { label: 'Another Link', href: '#' },
        { label: 'Disabled', href: '#', disabled: true }
      ]}
    />
  )
}

Style variants

Tabs

Set variant="tabs" on the base nav from above to generate a tabbed interface.

JSX
import { Nav, NavItem, NavLink } from '@chassis-ui/react'

export const Example = () => {
  return (
    <Nav variant="tabs">
      <NavItem>
        <NavLink href="#" active>
          Active
        </NavLink>
      </NavItem>
      <NavItem>
        <NavLink href="#">Link</NavLink>
      </NavItem>
      <NavItem>
        <NavLink href="#">Link</NavLink>
      </NavItem>
      <NavItem>
        <NavLink href="#" disabled>
          Disabled
        </NavLink>
      </NavItem>
    </Nav>
  )
}

Segments

Set variant="segments" instead for a segmented control, using the same markup. The variant was called pills before @chassis-ui/css 0.6: variant="pills" still renders it, and is deprecated.

JSX
import { Nav, NavItem, NavLink } from '@chassis-ui/react'

export const Example = () => {
  return (
    <Nav variant="segments">
      <NavItem>
        <NavLink href="#" active>
          Active
        </NavLink>
      </NavItem>
      <NavItem>
        <NavLink href="#">Link</NavLink>
      </NavItem>
      <NavItem>
        <NavLink href="#">Link</NavLink>
      </NavItem>
      <NavItem>
        <NavLink href="#" disabled>
          Disabled
        </NavLink>
      </NavItem>
    </Nav>
  )
}

Underline

Set variant="underline" to mark the active link with a line under it.

JSX
import { Nav, NavItem, NavLink } from '@chassis-ui/react'

export const Example = () => {
  return (
    <Nav variant="underline">
      <NavItem>
        <NavLink href="#" active>
          Active
        </NavLink>
      </NavItem>
      <NavItem>
        <NavLink href="#">Link</NavLink>
      </NavItem>
      <NavItem>
        <NavLink href="#">Link</NavLink>
      </NavItem>
      <NavItem>
        <NavLink href="#" disabled>
          Disabled
        </NavLink>
      </NavItem>
    </Nav>
  )
}

Sizes

Set size="sm" or size="lg" to scale the padding, gap, and font of the links. Every variant takes both; with no size, the nav has the medium size.

JSX
import { Nav, NavItem, NavLink } from '@chassis-ui/react'

const items = (
  <>
    <NavItem>
      <NavLink href="#" active>
        Active
      </NavLink>
    </NavItem>
    <NavItem>
      <NavLink href="#">Link</NavLink>
    </NavItem>
    <NavItem>
      <NavLink href="#">Link</NavLink>
    </NavItem>
  </>
)

export const Example = () => {
  return (
    <div className="d-flex flex-column align-items-start gap-md">
      <Nav variant="segments" size="sm">
        {items}
      </Nav>
      <Nav variant="segments">{items}</Nav>
      <Nav variant="segments" size="lg">
        {items}
      </Nav>
    </div>
  )
}

Alignment and layout

Flexbox utilities control a nav's horizontal alignment, stacking, and how its items fill the available width. Mix and match as needed.

Horizontal alignment

Navs are left-aligned by default. Apply .justify-content-center to center them:

JSX
import { Nav, NavItem, NavLink } from '@chassis-ui/react'

export const Example = () => {
  return (
    <Nav className="justify-content-center">
      <NavItem>
        <NavLink href="#" active>
          Active
        </NavLink>
      </NavItem>
      <NavItem>
        <NavLink href="#">Link</NavLink>
      </NavItem>
      <NavItem>
        <NavLink href="#">Link</NavLink>
      </NavItem>
      <NavItem>
        <NavLink href="#" disabled>
          Disabled
        </NavLink>
      </NavItem>
    </Nav>
  )
}

Or .justify-content-end to right-align them:

JSX
import { Nav, NavItem, NavLink } from '@chassis-ui/react'

export const Example = () => {
  return (
    <Nav className="justify-content-end">
      <NavItem>
        <NavLink href="#" active>
          Active
        </NavLink>
      </NavItem>
      <NavItem>
        <NavLink href="#">Link</NavLink>
      </NavItem>
      <NavItem>
        <NavLink href="#">Link</NavLink>
      </NavItem>
      <NavItem>
        <NavLink href="#" disabled>
          Disabled
        </NavLink>
      </NavItem>
    </Nav>
  )
}

Vertical stacking

Apply the .flex-column utility to stack nav items vertically instead of horizontally. Use a responsive variant (e.g. .sm:flex-column) to stack only below a given breakpoint.

JSX
import { Nav, NavItem, NavLink } from '@chassis-ui/react'

export const Example = () => {
  return (
    <Nav className="flex-column">
      <NavItem>
        <NavLink href="#" active>
          Active
        </NavLink>
      </NavItem>
      <NavItem>
        <NavLink href="#">Link</NavLink>
      </NavItem>
      <NavItem>
        <NavLink href="#">Link</NavLink>
      </NavItem>
      <NavItem>
        <NavLink href="#" disabled>
          Disabled
        </NavLink>
      </NavItem>
    </Nav>
  )
}

Fill and justify

Two modifier classes extend a nav's contents to the full available width. layout="fill" proportionately fills all available space with .nav-items — every item occupies the horizontal space, but not necessarily at equal widths.

JSX
import { Nav, NavItem, NavLink } from '@chassis-ui/react'

export const Example = () => {
  return (
    <Nav variant="segments" layout="fill">
      <NavItem>
        <NavLink href="#" active>
          Active
        </NavLink>
      </NavItem>
      <NavItem>
        <NavLink href="#">Link</NavLink>
      </NavItem>
      <NavItem>
        <NavLink href="#">Link</NavLink>
      </NavItem>
      <NavItem>
        <NavLink href="#" disabled>
          Disabled
        </NavLink>
      </NavItem>
    </Nav>
  )
}

layout="justified" instead gives every nav item an equal width, filling the same available space.

JSX
import { Nav, NavItem, NavLink } from '@chassis-ui/react'

export const Example = () => {
  return (
    <Nav variant="segments" layout="justified">
      <NavItem>
        <NavLink href="#" active>
          Active
        </NavLink>
      </NavItem>
      <NavItem>
        <NavLink href="#">Link</NavLink>
      </NavItem>
      <NavItem>
        <NavLink href="#">Link</NavLink>
      </NavItem>
      <NavItem>
        <NavLink href="#" disabled>
          Disabled
        </NavLink>
      </NavItem>
    </Nav>
  )
}

Flex utilities

Responsive nav variations can also be built from a series of flexbox utilities directly. This is more verbose than the layout prop, but offers finer control across breakpoints. The example below stacks the nav at the lowest breakpoint, then switches to a horizontal layout filling the available width starting from the sm breakpoint.

JSX
import { Nav, NavLink } from '@chassis-ui/react'

export const Example = () => {
  return (
    <Nav component="nav" variant="segments" className="flex-column sm:flex-row">
      <NavLink href="#" active>
        Active
      </NavLink>
      <NavLink href="#">Link</NavLink>
      <NavLink href="#">Link</NavLink>
      <NavLink href="#" disabled>
        Disabled
      </NavLink>
    </Nav>
  )
}

Using menus

A <Menu> composes into a nav alongside <NavItem>/<NavLink> pairs, adding a dropdown-style item to an otherwise flat navigation.

Tabs with menus

JSX
import { Nav, NavItem, NavLink, Menu, MenuToggle, MenuList, MenuItem } from '@chassis-ui/react'

export const Example = () => {
  return (
    <Nav>
      <NavItem>
        <NavLink href="#" active>
          Active
        </NavLink>
      </NavItem>
      <Menu component="li" className="nav-item">
        <MenuToggle color="secondary">Menu button</MenuToggle>
        <MenuList>
          <MenuItem href="#">Action</MenuItem>
          <MenuItem href="#">Another action</MenuItem>
          <MenuItem href="#">Something else here</MenuItem>
        </MenuList>
      </Menu>
      <NavItem>
        <NavLink href="#">Link</NavLink>
      </NavItem>
      <NavItem>
        <NavLink href="#" disabled>
          Disabled
        </NavLink>
      </NavItem>
    </Nav>
  )
}

Segments with menus

JSX
import { Nav, NavItem, NavLink, Menu, MenuToggle, MenuList, MenuItem } from '@chassis-ui/react'

export const Example = () => {
  return (
    <Nav variant="segments">
      <NavItem>
        <NavLink href="#" active>
          Active
        </NavLink>
      </NavItem>
      <Menu component="li" className="nav-item">
        <MenuToggle color="secondary">Menu button</MenuToggle>
        <MenuList>
          <MenuItem href="#">Action</MenuItem>
          <MenuItem href="#">Another action</MenuItem>
          <MenuItem href="#">Something else here</MenuItem>
        </MenuList>
      </Menu>
      <NavItem>
        <NavLink href="#">Link</NavLink>
      </NavItem>
      <NavItem>
        <NavLink href="#" disabled>
          Disabled
        </NavLink>
      </NavItem>
    </Nav>
  )
}

Overflow

A nav wraps onto further lines when its items don't fit. To keep it on one line and move the items that don't fit into a "More" menu instead, wrap it in a <NavOverflow>. Set keepVisible on a <NavItem> that should never move.

Accessibility

When using <Nav> to provide a navigation bar, add role="navigation" to the most logical parent container, or wrap a <nav> element around the whole navigation — not the <ul> itself, since that would prevent it from being announced as an actual list by assistive technology. <Nav> renders a plain list and sets no role of its own.

A navigation bar, even one visually styled as tabs via variant="tabs", shouldn't be given role="tablist", role="tab", or role="tabpanel" attributes. Those are only appropriate for dynamic tabbed interfaces, as described in the WAI ARIA Authoring Practices. <Nav> itself only renders the nav/nav-tabs/nav-segments styling and has no notion of a selected panel to wire up — reach for Tabs instead, which handles the full role="tablist"/role="tab"/role="tabpanel" + aria-selected/aria-controls/aria-labelledby pattern, keyboard navigation, and animated panel switching.

API

PropTypeDefault
asChild?boolean—
Render the single child element in place of this component's own element, with this component's classes, props and ref merged onto it: <Button asChild><Link href="/login">Log in</Link></Button>. The alternative to component for React Server Components — an element can be passed from the server to this package's client components, a component reference (component={Link}) can't.
className?string—
A string of all className you want applied to the base component.
component?ElementType—
Component used for the root node. Either a string to use a HTML element or a component.
items?NavItemDef[]—
Array of nav item definitions for data-driven rendering. When provided, children are ignored.
layout?"fill" | "justified"—
Specify a layout type for component.
ref?any—
size?"sm" | "lg"—
Size the component sm or lg.
variant?{ 'tabs' | 'segments' | 'underline' | 'pills' }—
Set the nav variant to tabs, to segments (a segmented control) or to underline, which underlines the active link. 'pills' is the former name of 'segments': deprecated, it renders the same.

Shape of each entry in Nav's items array (data-driven rendering).

PropTypeDefault
active?boolean—
Marks the item as active.
disabled?boolean—
Marks the item as disabled.
href?string—
URL for the nav link.
labelReactNode—
Label content for the nav item.
PropTypeDefault
active?boolean—
Toggle the active state for the component.
asChild?boolean—
Render the single child element in place of this component's own element, with this component's classes, props and ref merged onto it: <Button asChild><Link href="/login">Log in</Link></Button>. The alternative to component for React Server Components — an element can be passed from the server to this package's client components, a component reference (component={Link}) can't.
className?string—
A string of all className you want applied to the component.
color?ContextColor—
Sets the link color to one of Chassis context colors, including its interactive (:hover/:focus/:active/:visited) states.
component?ElementType—
Component used for the root node. Either a string to use a HTML element or a component.
disabled?boolean—
Toggle the disabled state for the component.
href?string—
The href attribute specifies the URL of the page the link goes to. Reaches an <a> or a component reference (a router link); dropped, with a warning in development, when component is another element. Declared explicitly here — rather than left to flow through generically from whatever C is — so consumers that wrap Link (MenuItem, ListItem, NavLink) can read it with a concrete type regardless of component.
iconLink?boolean—
Aligns a leading or trailing icon with the link text using flexbox, with a gap between them and an offset underline. Icons need to be passed as children alongside the text. Named iconLink rather than icon to avoid colliding with components (e.g. MenuItem) that already have their own, differently-typed icon prop for the icon content itself.
keepVisible?boolean—
Keeps the item in the list inside a NavOverflow, whatever the width.
onClick?MouseEventHandler<HTMLElement>—
Fires on click.
ref?Ref<HTMLLIElement>—
reset?boolean—
Removes the foreground color override, so the link inherits its color from the nearest ancestor instead of the default link color.
stretched?boolean—
Expands the link's click target to fill its positioned ancestor (the nearest ancestor with a position other than static).
type?"reset" | "button" | "submit"—
Specifies the type of button. Only applies when component="button". Different browsers may use different default types for the <button> element, so always specify it explicitly.
PropTypeDefault
active?boolean—
Toggle the active state for the component.
asChild?boolean—
Render the single child element in place of this component's own element, with this component's classes, props and ref merged onto it: <Button asChild><Link href="/login">Log in</Link></Button>. The alternative to component for React Server Components — an element can be passed from the server to this package's client components, a component reference (component={Link}) can't.
className?string—
A string of all className you want applied to the component.
color?ContextColor—
Sets the link color to one of Chassis context colors, including its interactive (:hover/:focus/:active/:visited) states.
component?ElementType—
Component used for the root node. Either a string to use a HTML element or a component.
disabled?boolean—
Toggle the disabled state for the component.
href?string—
The href attribute specifies the URL of the page the link goes to. Reaches an <a> or a component reference (a router link); dropped, with a warning in development, when component is another element. Declared explicitly here — rather than left to flow through generically from whatever C is — so consumers that wrap Link (MenuItem, ListItem, NavLink) can read it with a concrete type regardless of component.
iconLink?boolean—
Aligns a leading or trailing icon with the link text using flexbox, with a gap between them and an offset underline. Icons need to be passed as children alongside the text. Named iconLink rather than icon to avoid colliding with components (e.g. MenuItem) that already have their own, differently-typed icon prop for the icon content itself.
onClick?MouseEventHandler<HTMLElement>—
Fires on click.
ref?any—
reset?boolean—
Removes the foreground color override, so the link inherits its color from the nearest ancestor instead of the default link color.
stretched?boolean—
Expands the link's click target to fill its positioned ancestor (the nearest ancestor with a position other than static).
type?"button" | "reset" | "submit"—
Specifies the type of button. Only applies when component="button". Different browsers may use different default types for the <button> element, so always specify it explicitly.