Skip to main contentSkip to docs navigation

Build responsive site and application navigation with branding, nav links, forms, and a drawer-based mobile menu.

Depends onDrawer, Nav

Overview

The navbar is the primary navigation surface for a site or application. It composes a branding area, a set of navigation links, optional forms or text, and a drawer-based mobile menu — all wrapped in a single <nav> element (rendered by <Navbar>) that is responsive by default.

<Navbar> accepts a handful of sub-components as needed: <NavbarBrand> for a project or product name, <NavbarNav> for navigation links, <NavbarToggler> for opening the mobile <Drawer>, <NavbarText> for inline text, and standard form components for search boxes or other controls.

Basic usage

A complete navbar combines a <NavbarBrand>, a <NavbarToggler>, and a <Drawer> that holds the navigation below the expand breakpoint. The expand prop controls when the drawer's contents flow inline instead — set on a container-query basis, so the transition responds to the navbar's own width rather than the viewport width.

JSX
import { useState } from 'react'
import {
  Button,
  Container,
  Drawer,
  DrawerBody,
  DrawerHeader,
  DrawerTitle,
  Form,
  Icon,
  Menu,
  MenuDivider,
  MenuItem,
  MenuList,
  MenuToggle,
  Navbar,
  NavbarBrand,
  NavbarNav,
  NavbarToggler,
  NavItem,
  NavLink,
  TextInput
} from '@chassis-ui/react'

export const Example = () => {
  const [visible, setVisible] = useState(false)
  return (
    <Navbar expand="md" className="bg-even">
      <Container fluid>
        <NavbarBrand href="#">Navbar</NavbarBrand>
        <NavbarToggler
          aria-controls="navbarBasicUsage"
          aria-expanded={visible}
          aria-label="Toggle navigation"
          onClick={() => setVisible(!visible)}
        />
        <Drawer
          id="navbarBasicUsage"
          placement="end"
          visible={visible}
          onClose={() => setVisible(false)}
        >
          <DrawerHeader>
            <DrawerTitle>Menu</DrawerTitle>
          </DrawerHeader>
          <DrawerBody className="mb-sm md:mb-0">
            <NavbarNav className="me-auto">
              <NavItem>
                <NavLink href="#" active>
                  Home
                </NavLink>
              </NavItem>
              <NavItem>
                <NavLink href="#">Link</NavLink>
              </NavItem>
              <Menu component="li" className="nav-item">
                <MenuToggle component={NavLink}>Menu</MenuToggle>
                <MenuList>
                  <MenuItem href="#">Action</MenuItem>
                  <MenuItem href="#">Another action</MenuItem>
                  <MenuDivider />
                  <MenuItem href="#">Something else here</MenuItem>
                </MenuList>
              </Menu>
              <NavItem>
                <NavLink disabled>Disabled</NavLink>
              </NavItem>
            </NavbarNav>
            <Form className="hstack gap-sm" role="search">
              <TextInput type="search" placeholder="Search" aria-label="Search" />
              <Button
                type="submit"
                color="neutral"
                variant="smooth"
                className="icon-only"
                aria-label="Search"
              >
                <Icon name="search-solid" />
              </Button>
            </Form>
          </DrawerBody>
        </Drawer>
      </Container>
    </Navbar>
  )
}

Brand

<NavbarBrand> sets the project or product identity at the start of the navbar. It works on any element, but an anchor is the most common choice since the brand typically links to the home page.

JSX
import { Container, Navbar, NavbarBrand } from '@chassis-ui/react'

export const Example = () => {
  return (
    <Navbar className="bg-even">
      <Container fluid>
        <NavbarBrand href="#">Navbar</NavbarBrand>
      </Container>
    </Navbar>
  )
}

Replace the text with an <img> for an image-only brand.

JSX
import { Container, Navbar, NavbarBrand } from '@chassis-ui/react'

export const Example = () => {
  return (
    <Navbar className="bg-even">
      <Container fluid>
        <NavbarBrand href="#">
          <img src="https://placehold.co/24" alt="Navbar" width="24" height="24" />
        </NavbarBrand>
      </Container>
    </Navbar>
  )
}

Combine an image and text in the same brand element. The d-inline-block and align-text-top utilities keep the image aligned with the surrounding text baseline.

JSX
import { Container, Navbar, NavbarBrand } from '@chassis-ui/react'

export const Example = () => {
  return (
    <Navbar className="bg-even">
      <Container fluid>
        <NavbarBrand href="#">
          <img
            src="https://placehold.co/24"
            alt=""
            width="24"
            height="24"
            className="d-inline-block align-text-top"
          />
          <span className="ms-xs font-strong">Chassis</span>
        </NavbarBrand>
      </Container>
    </Navbar>
  )
}

Navbar navigation uses <NavbarNav> wrapping <NavItem>/<NavLink> pairs. Its links grow to occupy the available horizontal space once the navbar expands inline. Mark the current link with active, which renders aria-current="page".

JSX
import { useState } from 'react'
import {
  Container,
  Drawer,
  DrawerBody,
  DrawerHeader,
  DrawerTitle,
  Navbar,
  NavbarBrand,
  NavbarNav,
  NavbarToggler,
  NavItem,
  NavLink
} from '@chassis-ui/react'

export const Example = () => {
  const [visible, setVisible] = useState(false)
  return (
    <Navbar expand="sm" className="bg-even">
      <Container fluid>
        <NavbarBrand href="#">Navbar</NavbarBrand>
        <NavbarToggler
          aria-controls="navbarNav"
          aria-expanded={visible}
          aria-label="Toggle navigation"
          onClick={() => setVisible(!visible)}
        />
        <Drawer id="navbarNav" placement="end" visible={visible} onClose={() => setVisible(false)}>
          <DrawerHeader>
            <DrawerTitle>Menu</DrawerTitle>
          </DrawerHeader>
          <DrawerBody>
            <NavbarNav>
              <NavItem>
                <NavLink href="#" active>
                  Home
                </NavLink>
              </NavItem>
              <NavItem>
                <NavLink href="#">Link</NavLink>
              </NavItem>
              <NavItem>
                <NavLink href="#">About</NavLink>
              </NavItem>
              <NavItem>
                <NavLink disabled>Disabled</NavLink>
              </NavItem>
            </NavbarNav>
          </DrawerBody>
        </Drawer>
      </Container>
    </Navbar>
  )
}

The <NavItem>/<NavLink> pairing is optional — rendering <NavbarNav component="div"> with direct <NavLink> children produces the same result, and pairs naturally with the nav-segments class.

JSX
import { useState } from 'react'
import {
  Container,
  Drawer,
  DrawerBody,
  DrawerHeader,
  DrawerTitle,
  Navbar,
  NavbarBrand,
  NavbarNav,
  NavbarToggler,
  NavLink
} from '@chassis-ui/react'

export const Example = () => {
  const [visible, setVisible] = useState(false)
  return (
    <Navbar expand="sm" className="bg-even">
      <Container fluid>
        <NavbarBrand href="#">Navbar</NavbarBrand>
        <NavbarToggler
          aria-controls="navbarNavAltMarkup"
          aria-expanded={visible}
          aria-label="Toggle navigation"
          onClick={() => setVisible(!visible)}
        />
        <Drawer
          id="navbarNavAltMarkup"
          placement="end"
          visible={visible}
          onClose={() => setVisible(false)}
        >
          <DrawerHeader>
            <DrawerTitle>Menu</DrawerTitle>
          </DrawerHeader>
          <DrawerBody>
            <NavbarNav component="div" className="nav-segments">
              <NavLink href="#" active>
                Home
              </NavLink>
              <NavLink href="#">Link</NavLink>
              <NavLink href="#">About</NavLink>
              <NavLink disabled>Disabled</NavLink>
            </NavbarNav>
          </DrawerBody>
        </Drawer>
      </Container>
    </Navbar>
  )
}

<Menu> nests inside a <NavbarNav> with component="li" and className="nav-item", so the toggle and menu share the same nav item wrapper. Set <MenuToggle>'s own component to NavLink so the trigger renders with .nav-link styling instead of its default .button look.

JSX
import { useState } from 'react'
import {
  Container,
  Drawer,
  DrawerBody,
  DrawerHeader,
  DrawerTitle,
  Menu,
  MenuDivider,
  MenuItem,
  MenuList,
  MenuToggle,
  Navbar,
  NavbarBrand,
  NavbarNav,
  NavbarToggler,
  NavItem,
  NavLink
} from '@chassis-ui/react'

export const Example = () => {
  const [visible, setVisible] = useState(false)
  return (
    <Navbar expand="md" className="bg-even">
      <Container fluid>
        <NavbarBrand href="#">Navbar</NavbarBrand>
        <NavbarToggler
          aria-controls="navbarNavMenu"
          aria-expanded={visible}
          aria-label="Toggle navigation"
          onClick={() => setVisible(!visible)}
        />
        <Drawer
          id="navbarNavMenu"
          placement="end"
          visible={visible}
          onClose={() => setVisible(false)}
        >
          <DrawerHeader>
            <DrawerTitle>Menu</DrawerTitle>
          </DrawerHeader>
          <DrawerBody>
            <NavbarNav>
              <NavItem>
                <NavLink href="#" active>
                  Home
                </NavLink>
              </NavItem>
              <NavItem>
                <NavLink href="#">Link</NavLink>
              </NavItem>
              <NavItem>
                <NavLink href="#">About</NavLink>
              </NavItem>
              <Menu component="li" className="nav-item">
                <MenuToggle component={NavLink}>Menu</MenuToggle>
                <MenuList>
                  <MenuItem href="#">Action</MenuItem>
                  <MenuItem href="#">Another action</MenuItem>
                  <MenuDivider />
                  <MenuItem href="#">Something else here</MenuItem>
                </MenuList>
              </Menu>
            </NavbarNav>
          </DrawerBody>
        </Drawer>
      </Container>
    </Navbar>
  )
}

Forms

Form controls placed inside a navbar use the standard form components. The navbar's flex layout defaults to justify-content: space-between, so a brand at the start and a form at the end align automatically without additional utilities.

JSX
import { Button, Container, Form, Navbar, TextInput } from '@chassis-ui/react'

export const Example = () => {
  return (
    <Navbar className="bg-even">
      <Container fluid>
        <Form className="d-flex" role="search">
          <TextInput type="search" className="me-sm" placeholder="Search" aria-label="Search" />
          <Button type="submit" color="primary" variant="outline">
            Search
          </Button>
        </Form>
      </Container>
    </Navbar>
  )
}

The same form alongside a brand — the flex layout pushes the form to the opposite edge.

JSX
import { Button, Container, Form, Navbar, NavbarBrand, TextInput } from '@chassis-ui/react'

export const Example = () => {
  return (
    <Navbar className="bg-even">
      <Container fluid>
        <NavbarBrand href="#">Navbar</NavbarBrand>
        <Form className="d-flex" role="search">
          <TextInput type="search" className="me-sm" placeholder="Search" aria-label="Search" />
          <Button type="submit" color="primary" variant="outline">
            Search
          </Button>
        </Form>
      </Container>
    </Navbar>
  )
}

Input groups work too. When the navbar is essentially a form, rendering <Form> as the inner container saves a level of markup.

JSX
import { Button, Form, InputGroup, InputGroupAddon, Navbar, TextInput } from '@chassis-ui/react'

export const Example = () => {
  return (
    <Navbar className="bg-even">
      <Form className="container fluid">
        <InputGroup>
          <InputGroupAddon id="basic-addon1">@</InputGroupAddon>
          <TextInput placeholder="Username" aria-label="Username" aria-describedby="basic-addon1" />
          <Button type="submit" color="primary">
            Submit
          </Button>
        </InputGroup>
      </Form>
    </Navbar>
  )
}

Mixed button sizes inside a navbar form align via the same flex layout, with vertical alignment utilities available for finer adjustment.

JSX
import { Button, Form, Navbar } from '@chassis-ui/react'

export const Example = () => {
  return (
    <Navbar className="bg-even">
      <Form className="container fluid justify-content-start">
        <Button type="button" color="primary" variant="outline" className="me-sm">
          Main button
        </Button>
        <Button type="button" color="secondary" variant="outline" size="sm">
          Smaller button
        </Button>
        <button type="submit" hidden>
          Submit
        </button>
      </Form>
    </Navbar>
  )
}

Text

<NavbarText> adjusts vertical alignment and horizontal spacing for inline strings of text inside the navbar.

JSX
import { Container, Navbar, NavbarText } from '@chassis-ui/react'

export const Example = () => {
  return (
    <Navbar className="bg-even">
      <Container fluid>
        <NavbarText>Navbar text with an inline element</NavbarText>
      </Container>
    </Navbar>
  )
}

Text combines naturally with other navbar components inside the drawer body.

JSX
import { useState } from 'react'
import {
  Container,
  Drawer,
  DrawerBody,
  DrawerHeader,
  DrawerTitle,
  Navbar,
  NavbarBrand,
  NavbarNav,
  NavbarText,
  NavbarToggler,
  NavItem,
  NavLink
} from '@chassis-ui/react'

export const Example = () => {
  const [visible, setVisible] = useState(false)
  return (
    <Navbar expand="md" className="bg-even">
      <Container fluid>
        <NavbarBrand href="#">Navbar w/ text</NavbarBrand>
        <NavbarToggler
          aria-controls="navbarText"
          aria-expanded={visible}
          aria-label="Toggle navigation"
          onClick={() => setVisible(!visible)}
        />
        <Drawer id="navbarText" placement="end" visible={visible} onClose={() => setVisible(false)}>
          <DrawerHeader>
            <DrawerTitle>Menu</DrawerTitle>
          </DrawerHeader>
          <DrawerBody>
            <NavbarNav className="me-auto mb-sm md:mb-0">
              <NavItem>
                <NavLink href="#" active>
                  Home
                </NavLink>
              </NavItem>
              <NavItem>
                <NavLink href="#">Link</NavLink>
              </NavItem>
              <NavItem>
                <NavLink href="#">About</NavLink>
              </NavItem>
            </NavbarNav>
            <NavbarText>Navbar text with an inline element</NavbarText>
          </DrawerBody>
        </Drawer>
      </Container>
    </Navbar>
  )
}

Dark mode

Set data-cx-theme="dark" directly on <Navbar> to opt a single navbar into the dark theme regardless of the page's own color scheme.

JSX
import { useState } from 'react'
import {
  Container,
  Drawer,
  DrawerBody,
  DrawerHeader,
  DrawerTitle,
  Menu,
  MenuDivider,
  MenuItem,
  MenuList,
  MenuToggle,
  Navbar,
  NavbarBrand,
  NavbarNav,
  NavbarToggler,
  NavItem,
  NavLink
} from '@chassis-ui/react'

export const Example = () => {
  const [visible, setVisible] = useState(false)
  return (
    <Navbar expand="md" className="bg-even" data-cx-theme="dark">
      <Container fluid>
        <NavbarBrand href="#">Dark navbar</NavbarBrand>
        <NavbarToggler
          aria-controls="navbarDark"
          aria-expanded={visible}
          aria-label="Toggle navigation"
          onClick={() => setVisible(!visible)}
        />
        <Drawer id="navbarDark" placement="end" visible={visible} onClose={() => setVisible(false)}>
          <DrawerHeader>
            <DrawerTitle>Menu</DrawerTitle>
          </DrawerHeader>
          <DrawerBody className="mb-sm md:mb-0">
            <NavbarNav className="me-auto">
              <NavItem>
                <NavLink href="#" active>
                  Home
                </NavLink>
              </NavItem>
              <NavItem>
                <NavLink href="#">Link</NavLink>
              </NavItem>
              <Menu component="li" className="nav-item">
                <MenuToggle component={NavLink}>Menu</MenuToggle>
                <MenuList>
                  <MenuItem href="#">Action</MenuItem>
                  <MenuItem href="#">Another action</MenuItem>
                  <MenuDivider />
                  <MenuItem href="#">Something else here</MenuItem>
                </MenuList>
              </Menu>
              <NavItem>
                <NavLink disabled>Disabled</NavLink>
              </NavItem>
            </NavbarNav>
          </DrawerBody>
        </Drawer>
      </Container>
    </Navbar>
  )
}

Context variants

The color prop swaps the navbar's color palette to a semantic context, matching the context class family used across this library (Card, List, and others). Combine with variant="solid" for a saturated fill, className="bg-*" for a custom background, or data-cx-theme to mix theme and context independently.



JSX
import { useState } from 'react'
import {
  Button,
  Container,
  Drawer,
  DrawerBody,
  DrawerHeader,
  DrawerTitle,
  Form,
  Navbar,
  NavbarBrand,
  NavbarNav,
  NavbarToggler,
  NavItem,
  NavLink,
  TextInput
} from '@chassis-ui/react'

const NavLinks = () => (
  <NavbarNav className="me-auto mb-sm md:mb-0">
    <NavItem>
      <NavLink href="#" active>
        Home
      </NavLink>
    </NavItem>
    <NavItem>
      <NavLink href="#">Link</NavLink>
    </NavItem>
    <NavItem>
      <NavLink href="#">About</NavLink>
    </NavItem>
    <NavItem>
      <NavLink href="#">Contact</NavLink>
    </NavItem>
  </NavbarNav>
)

export const Example = () => {
  const [visibleSolid, setVisibleSolid] = useState(false)
  const [visibleDark, setVisibleDark] = useState(false)
  const [visibleLight, setVisibleLight] = useState(false)

  return (
    <>
      <Navbar expand="md" color="primary" variant="solid">
        <Container fluid>
          <NavbarBrand href="#">Navbar</NavbarBrand>
          <NavbarToggler
            aria-controls="navbarColorSolid"
            aria-expanded={visibleSolid}
            aria-label="Toggle navigation"
            onClick={() => setVisibleSolid(!visibleSolid)}
          />
          <Drawer
            id="navbarColorSolid"
            placement="end"
            visible={visibleSolid}
            onClose={() => setVisibleSolid(false)}
          >
            <DrawerHeader>
              <DrawerTitle>Menu</DrawerTitle>
            </DrawerHeader>
            <DrawerBody>
              <NavLinks />
              <Form className="d-flex" role="search">
                <TextInput
                  type="search"
                  className="me-sm"
                  placeholder="Search"
                  aria-label="Search"
                />
                <Button type="submit" color="default">
                  Search
                </Button>
              </Form>
            </DrawerBody>
          </Drawer>
        </Container>
      </Navbar>
      <br />
      <Navbar expand="md" color="primary" className="bg-even" data-cx-theme="dark">
        <Container fluid>
          <NavbarBrand href="#">Navbar</NavbarBrand>
          <NavbarToggler
            aria-controls="navbarColorDark"
            aria-expanded={visibleDark}
            aria-label="Toggle navigation"
            onClick={() => setVisibleDark(!visibleDark)}
          />
          <Drawer
            id="navbarColorDark"
            placement="end"
            visible={visibleDark}
            onClose={() => setVisibleDark(false)}
          >
            <DrawerHeader>
              <DrawerTitle>Menu</DrawerTitle>
            </DrawerHeader>
            <DrawerBody>
              <NavLinks />
              <Form className="d-flex" role="search">
                <TextInput
                  type="search"
                  className="me-sm"
                  data-cx-theme="light"
                  placeholder="Search"
                  aria-label="Search"
                />
                <Button type="submit" color="default">
                  Search
                </Button>
              </Form>
            </DrawerBody>
          </Drawer>
        </Container>
      </Navbar>
      <br />
      <Navbar expand="md" color="primary" className="bg-even" data-cx-theme="light">
        <Container fluid>
          <NavbarBrand href="#">Navbar</NavbarBrand>
          <NavbarToggler
            aria-controls="navbarColorLight"
            aria-expanded={visibleLight}
            aria-label="Toggle navigation"
            onClick={() => setVisibleLight(!visibleLight)}
          />
          <Drawer
            id="navbarColorLight"
            placement="end"
            visible={visibleLight}
            onClose={() => setVisibleLight(false)}
          >
            <DrawerHeader>
              <DrawerTitle>Menu</DrawerTitle>
            </DrawerHeader>
            <DrawerBody>
              <NavLinks />
              <Form className="d-flex" role="search">
                <TextInput
                  type="search"
                  className="me-sm"
                  placeholder="Search"
                  aria-label="Search"
                />
                <Button type="submit" color="primary" variant="outline">
                  Search
                </Button>
              </Form>
            </DrawerBody>
          </Drawer>
        </Container>
      </Navbar>
    </>
  )
}

Translucent

The translucent prop blurs and saturates whatever sits behind the navbar — useful when the navbar is positioned over a hero image, video, or scrollable content.

JSX
import { Container, Navbar, NavbarBrand, NavbarNav, NavItem, NavLink } from '@chassis-ui/react'

export const Example = () => {
  return (
    <Navbar expand="md" translucent>
      <Container fluid>
        <NavbarBrand href="#">Navbar</NavbarBrand>
        <NavbarNav>
          <NavItem>
            <NavLink href="#" active>
              Home
            </NavLink>
          </NavItem>
          <NavItem>
            <NavLink href="#">Link</NavLink>
          </NavItem>
          <NavItem>
            <NavLink href="#">About</NavLink>
          </NavItem>
        </NavbarNav>
      </Container>
    </Navbar>
  )
}

Containers

Wrapping <Navbar> in a <Container> centers it on the page; the inner <Container> is still required for the navbar's own padding. Placing the inner container directly inside <Navbar> instead centers only the navbar's contents while keeping its background full-width.

JSX
import { Container, Navbar, NavbarBrand } from '@chassis-ui/react'

export const Example = () => {
  return (
    <Container>
      <Navbar expand="lg" className="bg-even">
        <Container fluid>
          <NavbarBrand href="#">Navbar</NavbarBrand>
        </Container>
      </Navbar>
    </Container>
  )
}

Any responsive container variant is available to control how wide the navbar's contents appear.

JSX
import { Container, Navbar, NavbarBrand } from '@chassis-ui/react'

export const Example = () => {
  return (
    <Navbar expand="lg" className="bg-even">
      <Container fluidUntil="md">
        <NavbarBrand href="#">Navbar</NavbarBrand>
      </Container>
    </Navbar>
  )
}

Placement

The placement prop pulls the navbar out of normal flow or pins it during scroll: fixed-top/fixed-bottom use position: fixed and may require a compensating offset on the body (e.g. padding-top) to prevent content overlap; sticky-top/sticky-bottom use position: sticky.

JSX
import { useState, type ChangeEvent } from 'react'
import { Container, Navbar, NavbarBrand, Select } from '@chassis-ui/react'

type Placement = 'fixed-top' | 'fixed-bottom' | 'sticky-top' | 'sticky-bottom'

export const Example = () => {
  const [placement, setPlacement] = useState<Placement>('fixed-top')
  const handlePlacementChange = (e: ChangeEvent<HTMLSelectElement>) => {
    setPlacement(e.target.value as Placement)
  }
  return (
    <Navbar className="bg-even" placement={placement}>
      <Container fluid>
        <NavbarBrand>Navbar</NavbarBrand>
        <Select
          id="navbar-placement"
          aria-label="Navbar placement"
          className="w-auto"
          value={placement}
          onChange={handlePlacementChange}
          options={[
            { label: 'Fixed top', value: 'fixed-top' },
            { label: 'Fixed bottom', value: 'fixed-bottom' },
            { label: 'Sticky top', value: 'sticky-top' },
            { label: 'Sticky bottom', value: 'sticky-bottom' }
          ]}
        />
      </Container>
    </Navbar>
  )
}

Responsive behavior

The expand prop controls when the navbar transitions between drawer mode and inline mode, implemented with container queries so the transition responds to the navbar's own width:

  • expand="sm" — drawer below the sm breakpoint, inline at sm and above
  • expand="md" — drawer below md, inline at md and above
  • expand="lg" — drawer below lg, inline at lg and above
  • expand="xl" — drawer below xl, inline at xl and above
  • expand="2xl" — drawer below 2xl, inline at 2xl and above
  • expand={true} — inline at all widths (toggler hidden, drawer contents render flat inside the navbar)
  • expand omitted — drawer at all widths (toggler always visible, the drawer must be opened to access the nav)

Drawer placement

<Drawer>'s placement prop slides the panel in from any side. The examples below omit expand so the drawer stays visible regardless of viewport width.

JSX
import { useState } from 'react'
import {
  Container,
  Drawer,
  DrawerBody,
  DrawerHeader,
  DrawerTitle,
  Navbar,
  NavbarBrand,
  NavbarNav,
  NavbarToggler,
  NavItem,
  NavLink
} from '@chassis-ui/react'

export const Example = () => {
  const [visible, setVisible] = useState(false)
  return (
    <Navbar className="bg-even">
      <Container fluid>
        <NavbarBrand href="#">Left drawer</NavbarBrand>
        <NavbarToggler
          aria-controls="navbarLeftDrawer"
          aria-expanded={visible}
          aria-label="Toggle navigation"
          onClick={() => setVisible(!visible)}
        />
        <Drawer
          id="navbarLeftDrawer"
          placement="start"
          visible={visible}
          onClose={() => setVisible(false)}
        >
          <DrawerHeader>
            <DrawerTitle>Menu</DrawerTitle>
          </DrawerHeader>
          <DrawerBody>
            <NavbarNav className="me-auto mb-sm md:mb-0">
              <NavItem>
                <NavLink href="#" active>
                  Home
                </NavLink>
              </NavItem>
              <NavItem>
                <NavLink href="#">Link</NavLink>
              </NavItem>
              <NavItem>
                <NavLink disabled>Disabled</NavLink>
              </NavItem>
            </NavbarNav>
          </DrawerBody>
        </Drawer>
      </Container>
    </Navbar>
  )
}
JSX
import { useState } from 'react'
import {
  Container,
  Drawer,
  DrawerBody,
  DrawerHeader,
  DrawerTitle,
  Navbar,
  NavbarBrand,
  NavbarNav,
  NavbarToggler,
  NavItem,
  NavLink
} from '@chassis-ui/react'

export const Example = () => {
  const [visible, setVisible] = useState(false)
  return (
    <Navbar className="bg-even">
      <Container fluid>
        <NavbarBrand href="#">Top drawer</NavbarBrand>
        <NavbarToggler
          aria-controls="navbarTopDrawer"
          aria-expanded={visible}
          aria-label="Toggle navigation"
          onClick={() => setVisible(!visible)}
        />
        <Drawer
          id="navbarTopDrawer"
          placement="top"
          visible={visible}
          onClose={() => setVisible(false)}
        >
          <DrawerHeader>
            <DrawerTitle>Menu</DrawerTitle>
          </DrawerHeader>
          <DrawerBody>
            <NavbarNav className="me-auto mb-sm md:mb-0">
              <NavItem>
                <NavLink href="#" active>
                  Home
                </NavLink>
              </NavItem>
              <NavItem>
                <NavLink href="#">Link</NavLink>
              </NavItem>
              <NavItem>
                <NavLink disabled>Disabled</NavLink>
              </NavItem>
            </NavbarNav>
          </DrawerBody>
        </Drawer>
      </Container>
    </Navbar>
  )
}

Toggle button

<NavbarToggler> has no fixed position — its location within the navbar is determined by its order in the markup relative to other flex siblings. Placing it before <NavbarBrand> renders it on the left; placing it after renders it on the right. The flex container distributes spacing between siblings automatically, so no positioning utility classes are required.

With no <NavbarBrand> visible (the brand lives inside the drawer):

JSX
import { useState } from 'react'
import {
  Button,
  Container,
  Drawer,
  DrawerBody,
  DrawerHeader,
  DrawerTitle,
  Form,
  Navbar,
  NavbarBrand,
  NavbarNav,
  NavbarToggler,
  NavItem,
  NavLink,
  TextInput
} from '@chassis-ui/react'

export const Example = () => {
  const [visible, setVisible] = useState(false)
  return (
    <Navbar expand="md" className="bg-even">
      <Container fluid>
        <NavbarToggler
          aria-controls="navbarTogglerNoBrand"
          aria-expanded={visible}
          aria-label="Toggle navigation"
          onClick={() => setVisible(!visible)}
        />
        <Drawer
          id="navbarTogglerNoBrand"
          placement="end"
          visible={visible}
          onClose={() => setVisible(false)}
        >
          <DrawerHeader>
            <DrawerTitle>Hidden brand</DrawerTitle>
          </DrawerHeader>
          <DrawerBody>
            <NavbarBrand href="#">Hidden brand</NavbarBrand>
            <NavbarNav className="me-auto mb-sm md:mb-0">
              <NavItem>
                <NavLink href="#" active>
                  Home
                </NavLink>
              </NavItem>
              <NavItem>
                <NavLink href="#">Link</NavLink>
              </NavItem>
              <NavItem>
                <NavLink disabled>Disabled</NavLink>
              </NavItem>
            </NavbarNav>
            <Form className="d-flex" role="search">
              <TextInput type="search" className="me-sm" placeholder="Search" aria-label="Search" />
              <Button type="submit" color="success" variant="outline">
                Search
              </Button>
            </Form>
          </DrawerBody>
        </Drawer>
      </Container>
    </Navbar>
  )
}

External content

<Drawer> and <NavbarToggler> are only linked by the visible/onClose/onClick state a consumer wires between them, so the controlled drawer can live anywhere in the document — not necessarily inside <Navbar>. Use this when the controlled content is structurally separate from the navigation surface.

Collapsed content

Toggleable via the navbar toggler.
JSX
import { useState } from 'react'
import {
  Container,
  Drawer,
  DrawerBody,
  DrawerHeader,
  DrawerTitle,
  Navbar,
  NavbarToggler
} from '@chassis-ui/react'

export const Example = () => {
  const [visible, setVisible] = useState(false)
  return (
    <>
      <Drawer
        id="navbarToggleExternalContent"
        placement="top"
        data-cx-theme="dark"
        visible={visible}
        onClose={() => setVisible(false)}
      >
        <DrawerHeader>
          <DrawerTitle>Collapsed content</DrawerTitle>
        </DrawerHeader>
        <DrawerBody>
          <span className="fg-main">Toggleable via the navbar toggler.</span>
        </DrawerBody>
      </Drawer>
      <Navbar className="bg-main" data-cx-theme="dark">
        <Container fluid>
          <NavbarToggler
            aria-controls="navbarToggleExternalContent"
            aria-expanded={visible}
            aria-label="Toggle navigation"
            onClick={() => setVisible(!visible)}
          />
        </Container>
      </Navbar>
    </>
  )
}

When the controlled drawer precedes its toggler in document order, keyboard and assistive technology users may have trouble locating the newly revealed content. Move focus into the drawer on open (<Drawer> does this automatically), and keep aria-controls pointing at the drawer's id so the toggler-to-content relationship is exposed.

Accessibility

An accessible navbar relies on semantic markup and ARIA attributes that assistive technologies can interpret.

  • <Navbar> renders a <nav> element by default, exposing it as a landmark region. Pass an aria-label when a page has more than one navbar.
  • Mark the current page with active on the relevant <NavLink>, which renders aria-current="page".
  • <NavbarToggler> doesn't sync its ARIA attributes automatically — unlike the underlying CSS framework's vanilla JavaScript plugin, this component is a plain controlled button. Set aria-label, aria-controls (pointing at the drawer's id), and aria-expanded (kept in sync with the Drawer's own visible state) explicitly, as every example above does.

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 component.
color?ContextColor—
Sets the color of the component to one of Chassis context colors.
component?ElementType—
Component used for the root node. Either a string to use a HTML element or a component.
container?boolean | "sm" | "md" | "lg" | "xl" | "2xl" | "fluid"—
Wraps the children in a .container, as Container renders one: true for the default, 'fluid' for one as wide as the navbar, or a breakpoint for one that is fluid until it.
data-cx-theme?"dark" | "light"—
Opts this navbar into the framework's dark or light theming, independent of the page's own theme.
expand?boolean | Breakpoint—
Renders inline at and above this breakpoint, as a drawer below it. true renders inline at every width; omit to keep the drawer at every width.
placement?"fixed-top" | "fixed-bottom" | "sticky-top" | "sticky-bottom"—
Place component in non-static positions.
ref?any—
translucent?boolean—
Blurs and saturates whatever sits behind the navbar — useful when it's positioned over a hero image, video, or scrollable content.
variant?ContextStyle—
Sets the context style of the component. basic (the default) renders with no extra class.
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 component.
component?ElementType—
Component used for the root node. Either a string to use a HTML element or a component. Defaults to span, or a when href is set.
href?string—
The href attribute specifies the URL of the page the link goes to. Defaults component to a.
ref?any—
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 component.
component?ElementType—
Component used for the root node. Either a string to use a HTML element or a component.
ref?any—
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.
ref?any—
PropTypeDefault
className?string—
A string of all className you want applied to the base component.
icon?IconValue—
The toggler icon: an icon name, or an element of your own icon set. Defaults to IconProvider's menu icon.
label?stringToggle navigation
The accessible label announced by assistive technology when no children are provided.