The Navbar component displays site logos, navigation links, documentation tabs, and search triggers.
Using the Navbar primitive and its subcomponents, you can design a fully custom navigation bar. The following example shows how to build a header with active tab matching, search triggers, social integrations, and theme toggling:
// docs/components/CustomNavbar.tsx
import React, { useState } from 'react'
import { Navbar } from 'boltdocs/primitives'
import { useNavbar, useTheme, useSearch } from 'boltdocs/client'
export default function CustomNavbar () {
const { links , theme , logo , title } = useNavbar ()
const { toggleTheme } = useTheme ()
const { openSearch } = useSearch ()
const [ mobileOpen , setMobileOpen ] = useState ( false )
return (
< Navbar className = "bg-white/80 dark:bg-black/80 backdrop-blur-md border-b border-subtle" >
< Navbar.Content >
{ /* Left Section: Branding */ }
< Navbar.Left >
{logo && < Navbar.Logo src = {logo} alt = {title} href = "/" />}
< Navbar.Title className = "font-bold text-lg" >{title}</ Navbar.Title >
</ Navbar.Left >
{ /* Center Section: Main Navigation Links */ }
< Navbar.Center >
{links. map (( link ) => (
< Navbar.Link
key = {link.href}
href = {link.href}
label = {link.label}
className = {link.active ? 'text-primary font-medium' : 'text-muted' }
/>
))}
</ Navbar.Center >
{ /* Right Section: Actions */ }
< Navbar.Right >
{ /* Custom Search Dialog Trigger */ }
< Navbar.SearchTrigger onPress = {openSearch} />
{ /* Theme Toggle Button */ }
< Navbar.Theme
theme = {theme}
onThemeChange = {( isDark ) => toggleTheme ()}
/>
{ /* Github Social Button */ }
< Navbar.Socials icon = "github" link = "https://github.com/myorg/myrepo" />
{ /* Mobile Drawer Trigger (More Vertical Icon) */ }
< Navbar.More onPress = {() => setMobileOpen ( true )} className = "lg:hidden" />
</ Navbar.Right >
</ Navbar.Content >
{ /* Responsive Mobile Drawer Menu */ }
< Navbar.MobileMenu isOpen = {mobileOpen} onClose = {() => setMobileOpen ( false )}>
{links. map (( link ) => (
< Navbar.MobileLink
key = {link.href}
href = {link.href}
label = {link.label}
onPress = {() => setMobileOpen ( false )}
className = "text-lg py-2"
/>
))}
</ Navbar.MobileMenu >
</ Navbar >
Expand code
Below is a complete, production-ready reference implementation demonstrating how to build a fully-featured navigation bar (similar to the built-in theme navbar). It integrates version-switching dropdowns, language translation selectors, responsive sidebar toggling, sub-link menus, theme modes, and a responsive mobile menu:
// docs/components/ProductionNavbar.tsx
import React, { useState } from 'react'
import { Navbar, Menu, Button } from 'boltdocs/primitives'
import {
useNavbar,
useTheme,
useSearch,
useVersion,
useI18n,
useUI,
useLocation,
useLocalizedTo
} from 'boltdocs/client'
import { Menu as MenuIcon, X, ChevronDown, Languages } from 'lucide-react'
export default function ProductionNavbar () {
const { links , title , logo , logoProps , github , social , config } = useNavbar ()
const { theme , toggleTheme } = useTheme ()
const { openSearch } = useSearch ()
const { isSidebarOpen , toggleSidebar } = useUI ()
const { pathname } = useLocation ()
const [ mobileOpen , setMobileOpen ] = useState ( false )
// 1. Version Switch Dropdown Menu
const { currentVersionLabel , availableVersions , handleVersionChange } = useVersion ()
const VersionDropdown = availableVersions. length > 0 && (
< Menu.Trigger >
< Button className = "flex items-center gap-1.5 px-3 py-1.5 border rounded-xl text-xs bg-surface font-semibold text-body hover:bg-zinc-50 dark:hover:bg-zinc-900 transition-all" >
< span >{currentVersionLabel}</ span >
< ChevronDown size = { 14 } className = "opacity-60" />
</ Button >
< Menu.Root className = "w-40 bg-white dark:bg-zinc-900 border border-subtle rounded-xl p-1.5 shadow-md flex flex-col gap-0.5" >
< Menu.Section items = {availableVersions}>
{( version ) => (
< Menu.Item
key = {version.value}
onPress = {() => handleVersionChange (version.value)}
className = "px-3 py-2 text-xs rounded-lg hover:bg-zinc-100 dark:hover:bg-zinc-800 cursor-pointer outline-none"
>
{version.label}
</ Menu.Item >
)}
</ Menu.Section >
</ Menu.Root >
</ Menu.Trigger >
)
// 2. Language/i18n Dropdown Selector
const { currentLocale , availableLocales , handleLocaleChange } = useI18n ()
const LocaleDropdown = availableLocales. length > 0 && (
< Menu.Trigger >
< Button className = "flex items-center gap-1.5 px-3 py-1.5 border border-subtle bg-surface rounded-xl text-xs font-semibold text-body hover:bg-zinc-50 dark:hover:bg-zinc-900 transition-all" >
< Languages size = { 14 } className = "text-primary-500" />
< span className = "uppercase" >{currentLocale}</ span >
< ChevronDown size = { 14 } className = "opacity-60" />
</ Button >
< Menu.Root className = "w-40 bg-white dark:bg-zinc-900 border border-subtle rounded-xl p-1.5 shadow-md flex flex-col gap-0.5" >
< Menu.Section items = {availableLocales}>
{( locale ) => (
< Menu.Item
key = {locale.value}
onPress = {() => handleLocaleChange (locale.value)}
className = "px-3 py-2 text-xs rounded-lg hover:bg-zinc-100 dark:hover:bg-zinc-800 cursor-pointer outline-none"
>
{locale.label}
</ Menu.Item >
)}
</ Menu.Section >
</ Menu.Root >
</ Menu.Trigger >
)
return (
< Navbar className = "bg-main/80 backdrop-blur-md border-b border-subtle" >
< Navbar.Content >
{ /* Left Section: Mobile sidebar toggler, Logo, Title and Version Selection */ }
< Navbar.Left >
{pathname. startsWith ( '/docs' ) && (
< Button
onPress = {toggleSidebar}
className = "mr-2 lg:hidden p-1.5 text-muted hover:text-body rounded-lg hover:bg-surface transition-colors"
>
{isSidebarOpen ? < X size = { 20 } /> : < MenuIcon size = { 20 } />}
</ Button >
)}
{logo && < Navbar.Logo src = {logo} alt = {logoProps?.alt || title} href = "/" />}
< Navbar.Title href = "/" >{title}</ Navbar.Title >
< div className = "hidden sm:block" >
{VersionDropdown}
</ div >
</ Navbar.Left >
{ /* Center Section: Search dialog trigger bar */ }
< Navbar.Center >
< Navbar.SearchTrigger onPress = {openSearch} />
</ Navbar.Center >
{ /* Right Section: Navigation Links, i18n switcher, theme toggle, Github stars and socials */ }
< Navbar.Right >
{ /* Main Desktop Links */ }
< Navbar.Links >
{links. map (( link ) => {
const localizedHref = useLocalizedTo (link.href || '' )
const active = pathname === localizedHref || pathname. startsWith (localizedHref + '/' )
const hasItems = link.items && link.items. length > 0
if (hasItems) {
return (
< Navbar.Dropdown
key = {link.href}
label = {
< span className = { `px-2 py-1 font-medium transition-colors cursor-pointer ${
active ? 'text-primary' : 'text-muted hover:text-body'
}` }>
{link.label}
</ span >
}
>
{link.items?. map (( sub ) => (
< Navbar.DropdownItem
key = {sub.href}
href = { useLocalizedTo (sub.href || '' )}
label = {sub.label}
/>
))}
</ Navbar.Dropdown >
)
}
return (
< Navbar.Link
key = {link.href}
href = {localizedHref}
label = {link.label}
active = {active}
className = {active ? 'text-primary font-semibold' : 'text-muted hover:text-body' }
/>
)
})}
</ Navbar.Links >
{ /* Desktop utility settings */ }
< div className = "hidden sm:flex items-center gap-2" >
{LocaleDropdown}
< Navbar.Split className = "bg-subtle" />
</ div >
< Navbar.Theme theme = {theme} onThemeChange = {toggleTheme} />
{ /* Social connections (e.g., GitHub link button) */ }
{github && (
< Navbar.Socials icon = "github" link = {github} />
)}
{ /* "More" trigger for mobile drawers */ }
< Navbar.More onPress = {() => setMobileOpen ( true )} className = "lg:hidden" />
</ Navbar.Right >
</ Navbar.Content >
{ /* Mobile drawer menu overlay */ }
< Navbar.MobileMenu isOpen = {mobileOpen} onClose = {() => setMobileOpen ( false )}>
< div className = "flex flex-col gap-1" >
{links. map (( link ) => {
const localizedHref = useLocalizedTo (link.href || '' )
const active = pathname === localizedHref
return (
< Navbar.MobileLink
key = {link.href}
href = {localizedHref}
label = {link.label}
active = {active}
onPress = {() => setMobileOpen ( false )}
className = "text-lg py-2"
/>
)
})}
</ div >
{ /* Unified version and language selection list in mobile view */ }
< div className = "mt-6 border-t border-subtle pt-6 flex flex-col gap-4" >
< div className = "flex justify-between items-center px-4" >
< span className = "text-xs text-muted font-semibold uppercase" >Version</ span >
{VersionDropdown}
</ div >
< div className = "flex justify-between items-center px-4" >
< span className = "text-xs text-muted font-semibold uppercase" >Language</ span >
{LocaleDropdown}
</ div >
</ div >
</ Navbar.MobileMenu >
</ Navbar >
)
}
Expand code
The Navbar primitive provides the following subcomponents for structure customization:
Component HTML Tag Description Props Navbar.Root / Navbar<header>Main outer navbar container. ComponentBasePropsNavbar.Content<div>Centered layout container holding the inner flex elements. ComponentBasePropsNavbar.Left / Navbar.Center / Navbar.Right<div>Flex row alignment zones for logos, navigation links, and action buttons. ComponentBasePropsNavbar.Logo<img> wrapped in <a>Renders a brand image logo wrapped in a client Router link. Navbar.Logo PropsNavbar.Title<span>Renders a plain text typographic brand label. ComponentBasePropsNavbar.Link<a>Renders an optimized anchor link to a page route. Navbar.Link PropsNavbar.Dropdown<div>Collapsible trigger with an open/close state, optionally controlled. Navbar.Dropdown PropsNavbar.DropdownItem<a>A single item rendered inside a dropdown panel. Navbar.Link PropsNavbar.SearchTrigger<button>A fully accessible button to activate the search dialog. Navbar.SearchTrigger PropsNavbar.Theme<button>Renders an icon button to toggle light/dark mode. Navbar.Theme PropsNavbar.Socials<a>An icon social link shortcut (e.g., GitHub, Discord, Twitter). Navbar.Socials PropsNavbar.MobileMenu<div> (Modal)Responsive sliding modal drawer overlay for mobile screens. Navbar.MobileMenu PropsNavbar.MobileLink<a>Sized navigation items designed for mobile drawer menus. Navbar.MobileLink Props
Property Type Default Description childrenReactNodeundefinedChild content elements. classNamestringundefinedCustom utility CSS classes. styleCSSPropertiesundefinedInline style settings.
Property Type Default Description srcstringRequired Path to the logo image file. altstringRequired Accessibility alternative text. hrefstring'/'Target path when clicking the logo. widthnumber24Image width dimension. heightnumber24Image height dimension.
Property Type Default Description labelReactNodeRequired Label content text to display. hrefstringRequired Routing destination path. to'internal' | 'external''internal'Whether the navigation is internal routing or an external link.
Property Type Default Description labelReactNodeRequired The visible trigger text. childrenReactNodeRequired The dropdown panel content, e.g. one or more <Navbar.DropdownItem> rows. iconReactNode(down chevron) Custom indicator icon that replaces the default chevron. iconClassNamestringundefinedExtra classes for the indicator wrapper. openbooleanundefinedControlled open state. When omitted, the dropdown manages its own state. onOpenChange(open: boolean) => voidundefinedCallback fired when the dropdown open state changes. triggerClassNamestringundefinedExtra classes for the dropdown trigger row. panelClassNamestringundefinedExtra classes for the absolute-positioned popup wrapper. menuClassNamestringundefinedExtra classes for the styled dropdown panel.
Property Type Default Description onPress() => voidRequired Press trigger action callback.
Property Type Default Description theme'dark' | 'light'Required Active theme selection. onThemeChange(isSelected: boolean) => voidRequired Theme toggle change callback.
Property Type Default Description icon'github' | 'discord' | 'twitter'Required Target social network graphic icon. linkstringRequired URL link path.
Property Type Default Description isOpenbooleanfalseActive sliding visibility state. onClose() => voidRequired Close trigger callback. childrenReactNodeRequired Mobile drawer menu content cells.
Inherits all Navbar.Link props plus:
Property Type Default Description onPress() => voidundefinedCustom click callback (e.g., to auto-close drawers).
The Navbar primitive is style-neutral : it ships the header structure and interactive behavior, and every visual decision (colors, borders, spacing, sizes) belongs to the site theme through its className slots. It bakes in structural layout — the root <header> is sticky top-0 and Navbar.Content is a centered flex row — but no colors or borders. Interactive states are styled from CSS.
State / Slot Mechanism Navbar (root)<header> ships the sticky top-0 z-50 w-full layout; height, background, and border via classNameNavbar.ContentBaked-in centered flex row (justify-between); spacing via className Active link Navbar.Link emits no data-* attribute — compute it in the theme with useLocalizedTo/useLocation and apply className conditionallyNavbar.ThemeThe RAC ToggleButton emits data-selected when dark mode is active Navbar.More / Navbar.SearchTriggerThe RAC Button emits data-pressed while pressed Navbar.MobileMenuThe RAC modal overlay mounts only while open and emits data-entering/data-exiting during transitions
const { pathname } = useLocation ()
const href = useLocalizedTo ( '/docs/guides' )
const active = pathname === href || pathname. startsWith (href + '/' )
< Navbar className = "border-b border-subtle bg-main/80 backdrop-blur-md" >
< Navbar.Link
href = {href}
label = "Guides"
className = {active ? 'text-primary font-semibold' : 'text-muted hover:text-body' }
/>
< Navbar.Theme
theme = {theme}
onThemeChange = {toggleTheme}
className = "data-selected:text-primary-500"
/>
< Navbar.More onPress = {() => setMobileOpen ( true )} className = "data-pressed:bg-soft lg:hidden" />
</ Navbar >
Expand code
Last updated on October 18, 2026