Sidebar
App navigation on the inset background, in sections of items with captions.
import { Sidebar } from "@openperf/deft";
import { Preview } from "../../src/Preview";
export default function SidebarBasic() {
return (
<Preview overlay={true}>
<Sidebar.Provider>
<Sidebar.Trigger />
<Sidebar.Root>
<Sidebar.Content>
<Sidebar.Section>
<Sidebar.Caption>Section</Sidebar.Caption>
<Sidebar.Item href="#item-1">Item 1</Sidebar.Item>
<Sidebar.Item href="#item-2">Item 2</Sidebar.Item>
<Sidebar.Item href="#item-3">Item 3</Sidebar.Item>
</Sidebar.Section>
</Sidebar.Content>
</Sidebar.Root>
</Sidebar.Provider>
</Preview>
);
}
- Use it for product navigation in the application Shell:
Headerfor workspace identity, scrollableContentfor captioned sections, andFooterfor utilities and the user. - No border and no search. The current item has the selected fill.
- Pass
render={<Link to="…" />}to items when using a router link. - Put
RootandTriggerunder oneProviderso they share open state.Shell.Rootalready includesProvider. - From the
mdbreakpoint up,Rootis a sticky sidebar the height of the viewport andTriggeris hidden. Below it,Triggeropens the same navigation in a modal drawer with a backdrop and focus management; choosing an item closes it. Rootis labeled “Navigation” unless you pass anaria-label.
Header and footer
import { Avatar, Sidebar } from "@openperf/deft";
import { Preview } from "../../src/Preview";
export default function SidebarHeaderAndFooter() {
return (
<Preview overlay={true}>
<Sidebar.Provider>
<Sidebar.Trigger />
<Sidebar.Root>
<Sidebar.Header>
<Sidebar.Pill>
<Avatar.Root>A</Avatar.Root>
Workspace
</Sidebar.Pill>
</Sidebar.Header>
<Sidebar.Content>
<Sidebar.Item aria-current="page" href="#item-1">
Item 1
</Sidebar.Item>
<Sidebar.Item href="#item-2" trailing={12}>
Item 2
</Sidebar.Item>
</Sidebar.Content>
<Sidebar.Footer>
<Sidebar.Item href="#item-3">Item 3</Sidebar.Item>
<Sidebar.User avatar={<Avatar.Root>A</Avatar.Root>}>Name</Sidebar.User>
</Sidebar.Footer>
</Sidebar.Root>
</Sidebar.Provider>
</Preview>
);
}
- Docs, Support and Settings live in
Sidebar.FooterwithSidebar.User. - Counts go in
trailing, on the right in subtle text; alerts use a red Dot.
Nested and current items
import { Sidebar } from "@openperf/deft";
import { IconPlus } from "@tabler/icons-react";
import { Preview } from "../../src/Preview";
export default function SidebarNested() {
return (
<Preview overlay={true}>
<Sidebar.Provider>
<Sidebar.Trigger />
<Sidebar.Root>
<Sidebar.Content>
<Sidebar.Item href="#item-1" icon={IconPlus}>
Item 1
</Sidebar.Item>
<Sidebar.Item href="#item-2" icon={IconPlus} parent={true}>
Item 2
</Sidebar.Item>
<Sidebar.Item href="#item-2-1" level={1} parent={true}>
Item 2.1
</Sidebar.Item>
<Sidebar.Item aria-current="page" href="#item-2-1-1" level={2}>
Item 2.1.1
</Sidebar.Item>
</Sidebar.Content>
</Sidebar.Root>
</Sidebar.Provider>
</Preview>
);
}
level={1}andlevel={2}indent nested items and mute their text; top-level items keep the defaultlevel={0}.- Set
parenton each ancestor of the current item to strengthen its text and icon without the selected fill. aria-current="page"on the current-page link marks it as selected.activeapplies the selected style without settingaria-current. Onceactiveis set, it alone decides the style, so a router link that marks itself current before the page loads does not highlight early.
API
icon?TablerIcon
On Item. Leads the label.
TablerIcontrailing?ReactNode
On Item. Sits on the right, such as a count.
ReactNodeactive?boolean
On Item. Applies the selected style and ignores `aria-current` for styling.
booleanlevel?0 | 1 | 2
On Item. Indents nested items.
0 | 1 | 20parent?boolean
On Item. Strengthens the text and icon of an ancestor of the current item.
booleanavatar?ReactNode
On User. Leads the name.
ReactNoderender?ReactElement | function
On Item, Pill and User. Renders a router link or a menu trigger.
ReactElement | functionParts: Root, Caption, Content, Footer, Header, Item, Pill, Provider, Section, Trigger, User. Item renders an a, Pill and User a button, Content a nav and Root an aside, and Caption, Footer, Header and Section a div. Provider renders no element. Trigger takes the props of Button; an onClick that calls preventDefault() keeps the drawer closed.