Navigation bar
Navigation bars let people switch between UI views on smaller devices
Usage
Navigation bars (nav bars) provide access to three to five destinations.
Instalation
Run the following command:
npm i @radix-ui/react-slot
Copy and paste the following code into your project.
import * as React from 'react'
import { Slot } from '@radix-ui/react-slot'
import { cn } from '@/lib/utils'
const NavigationBarRoot = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
<aside
ref={ref}
className={cn(
'bottom-bar fixed inset-x-0 bottom-0 z-30 flex items-center bg-surfaceContainer py-4 pt-3',
className
)}
{...props}
/>
))
NavigationBarRoot.displayName = 'NavigationBar'
const NavigationBarContainer = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
<nav
ref={ref}
className={cn('flex grow items-center justify-around', className)}
{...props}
/>
))
NavigationBarContainer.displayName = 'NavigationBarContainer'
const iconStyle =
'group-data-[active]:duration-100 group-hover:font-emphasis z-0 group-data-[active]:font-filled group-hover:group-data-[active]:font-filled-emphasis'
const NavigationBarItemIcon = React.forwardRef<
HTMLSpanElement,
React.HTMLAttributes<HTMLSpanElement>
>(({ children, className, ...props }, ref) => (
<span
className={cn(
'relative grid h-8 w-16 place-items-center rounded-lg text-onSurface before:absolute before:inset-0 before:z-0 before:hidden before:animate-zoom-in-x before:rounded-2xl before:bg-secondaryContainer before:transition-colors group-data-[active]:before:block md:w-14'
)}
>
<Slot ref={ref} className={cn(iconStyle, className)} {...props}>
{children}
</Slot>
<span className="absolute inset-0 z-0 rounded-2xl bg-onSurfaceVariant opacity-0 transition-opacity group-hover:opacity-8 group-focus:opacity-12 group-active:opacity-12" />
</span>
))
NavigationBarItemIcon.displayName = 'NavigationBarItemIcon'
const NavigationBarItemLabel = React.forwardRef<
HTMLSpanElement,
React.HTMLAttributes<HTMLSpanElement>
>(({ className, children, ...props }, ref) => (
<span
ref={ref}
className={cn(
'w-full truncate text-center text-label-md font-normal text-onSurface group-hover:font-medium group-data-[active]:font-medium',
className
)}
{...props}
>
{children}
</span>
))
NavigationBarItemLabel.displayName = 'NavigationBarItemLabel'
interface NavigationBarItemProps
extends React.AnchorHTMLAttributes<HTMLAnchorElement> {
active?: boolean
asChild?: boolean
}
const itemStyle =
'relative group grid w-full place-items-center gap-y-1 font-normal outline-none p-0.5'
const NavigationBarItem = React.forwardRef<
HTMLAnchorElement,
NavigationBarItemProps
>(({ className, active, asChild, ...props }, ref) => {
const Comp = asChild ? Slot : 'a'
return (
<Comp
ref={ref}
data-active={active ? '' : undefined}
className={cn(itemStyle, className)}
{...props}
/>
)
})
NavigationBarItem.displayName = 'NavigationBarItem'
const NavigationBar = Object.assign(NavigationBarRoot, {
Container: NavigationBarContainer,
Item: NavigationBarItem,
ItemIcon: NavigationBarItemIcon,
ItemLabel: NavigationBarItemLabel,
})
const styles = {
icon: iconStyle,
item: itemStyle,
}
export {
NavigationBar,
NavigationBarRoot,
NavigationBarContainer,
NavigationBarItem,
NavigationBarItemIcon,
NavigationBarItemLabel,
styles,
}
Update the import paths to match your project setup.
Examples
Navigation Bar
Navigation bars (nav bars) provide access to three to five destinations.
The nav bar is positioned at the bottom of screens for convenient access. Each destination is represented by an icon and optional text label.
Recommended for small screens sizes, for bigger screens sizes see Navigation Rail.
News
import { useState } from 'react'
import { Fab } from '@/components/ui/fab'
import { Icon } from '@/components/ui/icon'
import { NavigationBar } from '@/components/ui/navigation-bar'
const navigationItem = (id: string, icon: string, label: string) => ({
id,
icon,
label,
})
const navigationItems = [
navigationItem('news', 'news', 'News'),
navigationItem('global', 'globe', 'Global'),
navigationItem('for-you', 'star', 'For you'),
navigationItem('trending', 'trending_up', 'Trending'),
navigationItem('archive', 'archive', 'Archive'),
]
export const NavigationBarExample = () => {
const [active, setActive] = useState('news')
return (
<div className="relative flex w-full flex-col">
<div className="relative grow">
<div className="p-4">
<h1 className="text-display-sm">
{navigationItems.find(({ id }) => id === active)?.label}
</h1>
</div>
</div>
<NavigationBar>
<NavigationBar.Container>
{navigationItems.map(({ id, icon, label }) => (
<NavigationBar.Item key={id} asChild active={id === active}>
<button onClick={() => setActive(id)}>
<NavigationBar.ItemIcon>
<Icon symbol={icon} />
</NavigationBar.ItemIcon>
<NavigationBar.ItemLabel>{label}</NavigationBar.ItemLabel>
</button>
</NavigationBar.Item>
))}
</NavigationBar.Container>
</NavigationBar>
</div>
)
}