Navbar
A responsive navigation header positioned on top side of the page that has affordances for branding, links, actions, etc.
import { Link } from "react-aria-components"import { Navbar, NavbarBrand, NavbarContent, NavbarItem } from "@opengovsg/oui"export const Example = () => { return ( <Navbar> <NavbarContent className="sm:hidden" justify="start"> <NavbarBrand> <p className="font-bold text-inherit">OUI</p> </NavbarBrand> </NavbarContent> <NavbarContent className="hidden gap-4 sm:flex" justify="center"> <NavbarBrand> <p className="font-bold text-inherit">OUI</p> </NavbarBrand> <NavbarItem> <Link href="#">Features</Link> </NavbarItem> <NavbarItem isActive> <Link aria-current="page" href="#"> Customers </Link> </NavbarItem> <NavbarItem> <Link href="#">Integrations</Link> </NavbarItem> </NavbarContent> <NavbarContent justify="end"> <NavbarItem> <Link href="#">Login</Link> </NavbarItem> </NavbarContent> </Navbar> )}Usage
import {
Navbar,
NavbarBrand,
NavbarContent,
NavbarItem,
NavbarMenu,
NavbarMenuItem,
NavbarMenuToggle,
} from "@opengovsg/oui"<Navbar>
<NavbarBrand>
<p className="font-bold">OUI</p>
</NavbarBrand>
<NavbarContent justify="center">
<NavbarItem>
<Link href="#">Features</Link>
</NavbarItem>
<NavbarItem isActive>
<Link href="#">Customers</Link>
</NavbarItem>
</NavbarContent>
<NavbarContent justify="end">
<NavbarItem>
<Link href="#">Login</Link>
</NavbarItem>
</NavbarContent>
</Navbar>Alternatively, install the component as local source via the shadcn CLI:
npx shadcn@latest add https://oui.open.gov.sg/r/navbar.jsonpnpm dlx shadcn@latest add https://oui.open.gov.sg/r/navbar.jsonnpx shadcn@latest add https://oui.open.gov.sg/r/navbar.jsonbunx --bun shadcn@latest add https://oui.open.gov.sg/r/navbar.jsonOUI exports 7 navbar-related components:
- Navbar: The main component of navbar.
- NavbarBrand: The component for branding.
- NavbarContent: The component for wrapping navbar items.
- NavbarItem: The component for navbar item.
- NavbarMenuToggle: The component for toggling navbar menu.
- NavbarMenu: The component for wrapping navbar menu items.
- NavbarMenuItem: The component for navbar menu item.
Examples
With Menu
You can use the NavbarMenuToggle and NavbarMenu components to display a togglable menu. This is commonly used for mobile navigation.
import { Link } from "react-aria-components"import { Navbar, NavbarBrand, NavbarContent, NavbarItem, NavbarMenu, NavbarMenuItem, NavbarMenuToggle,} from "@opengovsg/oui"const menuItems = [ "Profile", "Dashboard", "Activity", "Analytics", "System", "Deployments", "My Settings", "Team Settings", "Help & Feedback", "Log Out",]export const Example = () => { return ( <Navbar> <NavbarContent justify="start"> <NavbarMenuToggle className="sm:hidden" /> <NavbarMenu> {menuItems.map((item, index) => ( <NavbarMenuItem className={({ isActive }) => (isActive ? "font-semibold" : "")} isActive={index === 0} key={`${item}-${index}`} > <Link className="w-full" href="#"> {item} </Link> </NavbarMenuItem> ))} </NavbarMenu> <NavbarBrand> <p className="font-bold text-inherit">OUI</p> </NavbarBrand> </NavbarContent> <NavbarContent className="hidden gap-4 sm:flex" justify="center"> <NavbarItem> <Link href="#">Features</Link> </NavbarItem> <NavbarItem isActive> <Link aria-current="page" href="#"> Customers </Link> </NavbarItem> <NavbarItem> <Link href="#">Integrations</Link> </NavbarItem> </NavbarContent> <NavbarContent justify="end"> <NavbarItem> <Link href="#">Login</Link> </NavbarItem> </NavbarContent> </Navbar> )}Static
You can use the position prop to make the navbar static positioned (the default behavior is sticky).
import { Link } from "react-aria-components"import { Navbar, NavbarBrand, NavbarContent, NavbarItem } from "@opengovsg/oui"export const Example = () => { return ( <Navbar position="static"> <NavbarBrand> <p className="font-bold text-inherit">OUI</p> </NavbarBrand> <NavbarContent className="hidden gap-4 sm:flex" justify="center"> <NavbarItem> <Link href="#">Features</Link> </NavbarItem> <NavbarItem isActive> <Link aria-current="page" href="#"> Customers </Link> </NavbarItem> <NavbarItem> <Link href="#">Integrations</Link> </NavbarItem> </NavbarContent> <NavbarContent justify="end"> <NavbarItem> <Link href="#">Login</Link> </NavbarItem> </NavbarContent> </Navbar> )}Show on Scroll Up
You can use the shouldShowOnScrollUp prop to make the navbar show when the user scrolls up. This is useful for providing quick access to navigation while maximizing content visibility.
Note: This prop only takes effect when
positionis set tostatic.
import { Link } from "react-aria-components"import { Navbar, NavbarBrand, NavbarContent, NavbarItem, NavbarMenu, NavbarMenuItem, NavbarMenuToggle,} from "@opengovsg/oui"const menuItems = ["Profile", "Dashboard", "Settings", "Log Out"]export const Example = () => { return ( <Navbar position="static" shouldShowOnScrollUp> <NavbarContent justify="start"> <NavbarMenuToggle className="sm:hidden" /> <NavbarMenu> {menuItems.map((item, index) => ( <NavbarMenuItem key={`${item}-${index}`}> <Link className="w-full" href="#"> {item} </Link> </NavbarMenuItem> ))} </NavbarMenu> <NavbarBrand> <p className="font-bold text-inherit">OUI</p> </NavbarBrand> </NavbarContent> <NavbarContent className="hidden gap-4 sm:flex" justify="center"> <NavbarItem> <Link href="#">Features</Link> </NavbarItem> <NavbarItem isActive> <Link aria-current="page" href="#"> Customers </Link> </NavbarItem> <NavbarItem> <Link href="#">Integrations</Link> </NavbarItem> </NavbarContent> <NavbarContent justify="end"> <NavbarItem> <Link href="#">Login</Link> </NavbarItem> </NavbarContent> </Navbar> )}Controlled Menu
You can use the isMenuOpen and onMenuOpenChange props to control the navbar menu state programmatically.
import { useState } from "react"import { Link } from "react-aria-components"import { Button, Navbar, NavbarBrand, NavbarContent, NavbarItem, NavbarMenu, NavbarMenuItem, NavbarMenuToggle,} from "@opengovsg/oui"const menuItems = ["Profile", "Dashboard", "Settings", "Log Out"]export const Example = () => { const [isMenuOpen, setIsMenuOpen] = useState(false) return ( <Navbar isMenuOpen={isMenuOpen} onMenuOpenChange={setIsMenuOpen}> <NavbarContent justify="start"> <NavbarMenuToggle className="sm:hidden" /> <NavbarMenu> {menuItems.map((item, index) => ( <NavbarMenuItem key={`${item}-${index}`}> <Link className="w-full" href="#"> {item} </Link> </NavbarMenuItem> ))} </NavbarMenu> <NavbarBrand> <p className="font-bold text-inherit">OUI</p> </NavbarBrand> </NavbarContent> <NavbarContent className="hidden gap-4 sm:flex" justify="center"> <NavbarItem> <Link href="#">Features</Link> </NavbarItem> <NavbarItem> <Link href="#">Customers</Link> </NavbarItem> </NavbarContent> <NavbarContent justify="end"> <NavbarItem> <Button size="sm" onPress={() => setIsMenuOpen(!isMenuOpen)}> {isMenuOpen ? "Close" : "Open"} Menu </Button> </NavbarItem> </NavbarContent> </Navbar> )}Without Border
By default, the navbar has a bottom border. You can use the hasBorder prop to control its visibility.
Set hasBorder={false} to remove the bottom border from the navbar.
import { Link } from "react-aria-components"import { Navbar, NavbarBrand, NavbarContent, NavbarItem } from "@opengovsg/oui"export const Example = () => { return ( <Navbar hasBorder={false}> <NavbarBrand> <p className="font-bold text-inherit">OUI</p> </NavbarBrand> <NavbarContent className="hidden gap-4 sm:flex" justify="center"> <NavbarItem> <Link href="#">Features</Link> </NavbarItem> <NavbarItem isActive> <Link aria-current="page" href="#"> Customers </Link> </NavbarItem> <NavbarItem> <Link href="#">Integrations</Link> </NavbarItem> </NavbarContent> <NavbarContent justify="end"> <NavbarItem> <Link href="#">Login</Link> </NavbarItem> </NavbarContent> </Navbar> )}Customizing the Active Item
When the NavbarItem has isActive set to true, it will have a data-active attribute. You can use this attribute to customize the active state styling.
import { Link } from "react-aria-components"import { Navbar, NavbarBrand, NavbarContent, NavbarItem } from "@opengovsg/oui"export const Example = () => { return ( <Navbar> <NavbarBrand> <p className="font-bold text-inherit">OUI</p> </NavbarBrand> <NavbarContent className="hidden gap-4 sm:flex" justify="center"> <NavbarItem> <Link href="#">Features</Link> </NavbarItem> <NavbarItem isActive className="data-[active=true]:text-interaction-links-default data-[active=true]:font-semibold" > <Link aria-current="page" href="#"> Customers </Link> </NavbarItem> <NavbarItem> <Link href="#">Integrations</Link> </NavbarItem> </NavbarContent> <NavbarContent justify="end"> <NavbarItem> <Link href="#">Login</Link> </NavbarItem> </NavbarContent> </Navbar> )}Slots
- base: The main slot for the navbar. It takes the full width of the parent and wraps the navbar elements including the menu.
- wrapper: The slot that contains the navbar elements such as
brand,contentandtoggle. - brand: The slot for the
NavbarBrandcomponent. - content: The slot for the
NavbarContentcomponent. - item: The slot for the
NavbarItemcomponent. - toggle: The slot for the
NavbarMenuTogglecomponent. - toggleIcon: The slot for the
NavbarMenuToggleicon. - menu: The slot for the
NavbarMenucomponent. - menuItem: The slot for the
NavbarMenuItemcomponent.
Data Attributes
Navbar has the following attributes on the base element:
- data-menu-open: Indicates if the navbar menu is open.
- data-hidden: Indicates if the navbar is hidden. Used when the
shouldShowOnScrollUpprop istrue.
NavbarContent:
- data-justify: The justify content of the navbar content (
start,center, orend).
NavbarItem has the following attributes on the base element:
- data-active: Indicates if the navbar item is active. Set when the
isActiveprop istrue.
NavbarMenuToggle has the following attributes on the base element:
- data-open: Indicates if the navbar menu is open.
- data-pressed: When the navbar menu toggle is pressed.
- data-hover: When the navbar menu toggle is being hovered.
- data-focus-visible: When the navbar menu toggle is being focused with the keyboard.
NavbarMenuItem has the following attributes on the base element:
- data-active: Indicates if the menu item is active. Set when the
isActiveprop istrue. - data-open: Indicates if the navbar menu is open.
API Reference
Navbar Props
| Prop | Type | Default | Description |
|---|---|---|---|
| children | ReactNode | - | The content of the navbar |
| height | string | number | "4rem" | The height of the navbar |
| position | "static" | "sticky" | "sticky" | The CSS position of the navbar |
| hasBorder | boolean | true | Whether to show a bottom border |
| isMenuOpen | boolean | false | Whether the menu is open (controlled) |
| isMenuDefaultOpen | boolean | false | Whether the menu should be open by default |
| shouldBlockScroll | boolean | true | Whether to block scroll when menu is open |
| shouldShowOnScrollUp | boolean | false | Whether to show navbar when scrolling up (only works with position="static") |
| disableScrollHandler | boolean | false | Whether to disable the scroll event handler |
| classNames | Record<Slot, string> | - | Classes to apply to each slot |
Navbar Events
| Prop | Type | Description |
|---|---|---|
| onMenuOpenChange | (isOpen: boolean) => void | Handler called when the menu open state changes |
| onScrollPositionChange | (scrollPosition: number) => void | Handler called when scroll position changes |
NavbarContent Props
| Prop | Type | Default | Description |
|---|---|---|---|
| children | ReactNode | - | The content items |
| justify | "start" | "center" | "end" | "start" | The justify content alignment |
NavbarItem Props
| Prop | Type | Default | Description |
|---|---|---|---|
| children | ReactNode | - | The content of the item |
| isActive | boolean | false | Whether the item is active |
NavbarMenuToggle Props
| Prop | Type | Default | Description |
|---|---|---|---|
| icon | ReactNode | ((isOpen: boolean) => ReactNode) | - | Custom icon to display |
| size | "xs" | "sm" | "md" | "lg" | "sm" | The size of the toggle button |
| classNames | Record<"toggle" | "toggleIcon", string> | - | Classes for toggle slots |
NavbarMenu Props
| Prop | Type | Default | Description |
|---|---|---|---|
| children | ReactNode | - | The menu items |
| portalContainer | Element | Below navbar | The container for the menu portal |
NavbarMenuItem Props
| Prop | Type | Default | Description |
|---|---|---|---|
| children | ReactNode | - | The content of the menu item |
| isActive | boolean | false | Whether the menu item is active |
| className | string | ((props: { isActive: boolean }) => string) | - | Class name or render function |