Getting Started
Components
- Accordion
- Alert
- Alert Dialog
- Avatar
- Badge
- Button
- Calendar
- Card
- Carousel
- Chart
- Checkbox
- Circular Progress
- Collapsible
- Compare Slider
- Dialog
- Dropdown Menu
- Gauge
- Input
- Label
- Marquee
- Navigation Menu
- Number Field
- Pagination
- Popover
- Progress
- Radio Group
- Scroll Area
- Select
- Separator
- Sheet
- Sidebar
- Skeleton
- Slider
- Switch
- Table
- Tabs
- Textarea
- Toggle
- Tooltip
Demos
A static sidebar with a header, a labelled group of links, a badge, and a footer.
PREDICT
Health
- 3
"use client"
import {
ActivityIcon,
CalendarIcon,
FileTextIcon,
HomeIcon,
SettingsIcon,
} from "lucide-react"
import {
Sidebar,
SidebarContent,
SidebarFooter,
SidebarGroup,
SidebarGroupContent,
SidebarGroupLabel,
SidebarHeader,
SidebarMenu,
SidebarMenuBadge,
SidebarMenuButton,
SidebarMenuItem,
SidebarProvider,
} from "@workspace/ui/components/sidebar"
const items = [
{ title: "Home", icon: HomeIcon, active: true },
{ title: "Biomarkers", icon: ActivityIcon, badge: 3 },
{ title: "Reports", icon: FileTextIcon },
{ title: "Appointments", icon: CalendarIcon },
]
export function SidebarDemo() {
return (
<SidebarProvider className="min-h-0 w-auto">
<Sidebar collapsible="none" className="h-96 rounded-lg border">
<SidebarHeader>
<p className="px-2 text-sm font-medium">PREDICT</p>
</SidebarHeader>
<SidebarContent>
<SidebarGroup>
<SidebarGroupLabel>Health</SidebarGroupLabel>
<SidebarGroupContent>
<SidebarMenu>
{items.map((item) => (
<SidebarMenuItem key={item.title}>
<SidebarMenuButton isActive={item.active}>
<item.icon />
<span>{item.title}</span>
</SidebarMenuButton>
{item.badge ? <SidebarMenuBadge>{item.badge}</SidebarMenuBadge> : null}
</SidebarMenuItem>
))}
</SidebarMenu>
</SidebarGroupContent>
</SidebarGroup>
</SidebarContent>
<SidebarFooter>
<SidebarMenu>
<SidebarMenuItem>
<SidebarMenuButton>
<SettingsIcon />
<span>Settings</span>
</SidebarMenuButton>
</SidebarMenuItem>
</SidebarMenu>
</SidebarFooter>
</Sidebar>
</SidebarProvider>
)
}
Usage
Use the sidebar for the main navigation of an app with several top-level sections. Wrap the layout in SidebarProvider and put the page in SidebarInset. On mobile the sidebar opens as a Sheet.
Import it from @workspace/ui/components/sidebar.
Anatomy
- SidebarProvider — Holds the open state and handles the Cmd/Ctrl + B shortcut.
- Sidebar — The panel. Sets side, variant, and how it collapses.
- SidebarHeader and SidebarFooter — Fixed areas at the top and bottom.
- SidebarContent — The scrolling middle.
- SidebarInput — A compact search field for the header.
- SidebarSeparator — A line between groups.
- SidebarGroup, SidebarGroupLabel, SidebarGroupContent — A labelled section.
- SidebarGroupAction — A small button in the corner of a group, such as "Add".
- SidebarMenu, SidebarMenuItem, SidebarMenuButton — The list of items. Buttons by default.
- SidebarMenuBadge, SidebarMenuAction — A count and a trailing button on an item.
- SidebarMenuSub, SidebarMenuSubItem, SidebarMenuSubButton — Nested links. The sub button renders an anchor.
- SidebarMenuSkeleton — A loading row for a menu.
- SidebarTrigger — A button that toggles the sidebar.
- SidebarRail — A thin edge strip that toggles the sidebar on click.
- SidebarInset — The main content area next to the sidebar.
- useSidebar — Hook that returns
state,open,setOpen,openMobile,setOpenMobile,isMobile, andtoggleSidebar.
Notes
- The open state is written to the
sidebar_statecookie. Read it on the server and pass it todefaultOpento keep the state across reloads. - With
collapsible="icon", settooltipon each SidebarMenuButton so the label is still available when only the icon shows. - Mark the current page with
isActive. - To render a link, pass an anchor through
renderon SidebarMenuButton.
Examples
Groups
Split links into labelled groups with SidebarSeparator between them.
Health
Account
"use client"
import {
ActivityIcon,
BellIcon,
HeartPulseIcon,
HomeIcon,
UserIcon,
} from "lucide-react"
import {
Sidebar,
SidebarContent,
SidebarGroup,
SidebarGroupContent,
SidebarGroupLabel,
SidebarMenu,
SidebarMenuButton,
SidebarMenuItem,
SidebarProvider,
SidebarSeparator,
} from "@workspace/ui/components/sidebar"
const groups = [
{
label: "Health",
items: [
{ title: "Home", icon: HomeIcon },
{ title: "Biomarkers", icon: ActivityIcon },
{ title: "Heart", icon: HeartPulseIcon },
],
},
{
label: "Account",
items: [
{ title: "Profile", icon: UserIcon },
{ title: "Notifications", icon: BellIcon },
],
},
]
export function SidebarGroups() {
return (
<SidebarProvider className="min-h-0 w-auto">
<Sidebar collapsible="none" className="h-96 rounded-lg border">
<SidebarContent>
{groups.map((group, index) => (
<div key={group.label}>
{index > 0 ? <SidebarSeparator /> : null}
<SidebarGroup>
<SidebarGroupLabel>{group.label}</SidebarGroupLabel>
<SidebarGroupContent>
<SidebarMenu>
{group.items.map((item) => (
<SidebarMenuItem key={item.title}>
<SidebarMenuButton>
<item.icon />
<span>{item.title}</span>
</SidebarMenuButton>
</SidebarMenuItem>
))}
</SidebarMenu>
</SidebarGroupContent>
</SidebarGroup>
</div>
))}
</SidebarContent>
</Sidebar>
</SidebarProvider>
)
}
Submenu
Nest links under an item with SidebarMenuSub.
"use client"
import { ActivityIcon, FileTextIcon, HomeIcon } from "lucide-react"
import {
Sidebar,
SidebarContent,
SidebarGroup,
SidebarGroupContent,
SidebarMenu,
SidebarMenuButton,
SidebarMenuItem,
SidebarMenuSub,
SidebarMenuSubButton,
SidebarMenuSubItem,
SidebarProvider,
} from "@workspace/ui/components/sidebar"
const categories = ["Heart", "Metabolic", "Hormones", "Inflammation"]
export function SidebarSubmenu() {
return (
<SidebarProvider className="min-h-0 w-auto">
<Sidebar collapsible="none" className="h-96 rounded-lg border">
<SidebarContent>
<SidebarGroup>
<SidebarGroupContent>
<SidebarMenu>
<SidebarMenuItem>
<SidebarMenuButton>
<HomeIcon />
<span>Home</span>
</SidebarMenuButton>
</SidebarMenuItem>
<SidebarMenuItem>
<SidebarMenuButton>
<ActivityIcon />
<span>Biomarkers</span>
</SidebarMenuButton>
<SidebarMenuSub>
{categories.map((category) => (
<SidebarMenuSubItem key={category}>
<SidebarMenuSubButton href="#" isActive={category === "Heart"}>
<span>{category}</span>
</SidebarMenuSubButton>
</SidebarMenuSubItem>
))}
</SidebarMenuSub>
</SidebarMenuItem>
<SidebarMenuItem>
<SidebarMenuButton>
<FileTextIcon />
<span>Reports</span>
</SidebarMenuButton>
</SidebarMenuItem>
</SidebarMenu>
</SidebarGroupContent>
</SidebarGroup>
</SidebarContent>
</Sidebar>
</SidebarProvider>
)
}
Props
These are the props you set most often. Unlisted props pass through to the underlying element.
SidebarProvider
| Prop | Type | Default | Description |
|---|---|---|---|
defaultOpen | boolean | true | Open on first render. |
open | boolean | — | Open state when controlled. |
onOpenChange | (open) => void | — | Called when the state changes. |
Sidebar
| Prop | Type | Default | Description |
|---|---|---|---|
side | "left" or "right" | left | Edge of the screen. |
variant | "sidebar", "floating", or "inset" | sidebar | Visual style. |
collapsible | "offcanvas", "icon", or "none" | offcanvas | How the sidebar collapses. |
SidebarMenuButton
| Prop | Type | Default | Description |
|---|---|---|---|
isActive | boolean | false | Marks the current page. |
variant | "default" or "outline" | default | Visual style. |
size | "default", "sm", or "lg" | default | Height of the button. |
tooltip | string or TooltipContent props | — | Shown when the sidebar is collapsed to icons. |
render | ReactElement | — | Element to render instead of a button. |
SidebarMenuAction
| Prop | Type | Default | Description |
|---|---|---|---|
showOnHover | boolean | false | Hide the action until the item is hovered or focused. |
SidebarMenuSubButton
| Prop | Type | Default | Description |
|---|---|---|---|
isActive | boolean | false | Marks the current page. |
size | "sm" or "md" | md | Size of the link. |
render | ReactElement | — | Element to render instead of an anchor. |
SidebarMenuSkeleton
| Prop | Type | Default | Description |
|---|---|---|---|
showIcon | boolean | false | Show an icon placeholder before the text. |