Sidebar
App-shell sidebar primitives for full-page navigation layouts.
Overview
Sidebar provides the frame for an application shell: persistent navigation, a
collapsible desktop rail, a mobile sheet, and an inset content region.
Open app shell example
Layout
import {
Card,
SidebarInset,
SidebarProvider,
} from "@tilt-legal/cubitt-components/primitives";
export default function Page() {
return (
<SidebarProvider>
<AppSidebar />
<SidebarInset>
<div className="flex flex-1 flex-col gap-4 p-4">
<div className="grid auto-rows-min gap-4 md:grid-cols-3">
<Card className="aspect-video" />
<Card className="aspect-video" />
<Card className="aspect-video" />
</div>
<Card className="min-h-[100vh] flex-1 md:min-h-min" />
</div>
</SidebarInset>
</SidebarProvider>
);
}App Sidebar
import { Sidebar } from "@tilt-legal/cubitt-components/primitives";
export function AppSidebar(props: React.ComponentProps<typeof Sidebar>) {
return (
<Sidebar variant="inset" {...props}>
<AppSidebarHeader matters={data.matters} />
<AppSidebarMain groups={data.navGroups} />
<AppSidebarFooter
isOrgAdmin={data.isOrgAdmin}
organisationName={data.organisationName}
user={data.user}
/>
</Sidebar>
);
}Collapsible Groups
Use render to pass sidebar buttons into other primitives. This is Cubitt's
replacement for shadcn-style asChild.
import {
Collapsible,
CollapsiblePanel,
CollapsibleTrigger,
SidebarGroup,
SidebarGroupLabel,
SidebarMenu,
SidebarMenuButton,
SidebarMenuItem,
SidebarMenuSub,
SidebarMenuSubButton,
SidebarMenuSubItem,
} from "@tilt-legal/cubitt-components/primitives";
import { ChevronRight } from "@tilt-legal/cubitt-icons/ui/outline";
import { useState } from "react";
export function SidebarNavGroup({ items }) {
return (
<SidebarGroup>
<SidebarGroupLabel>Platform</SidebarGroupLabel>
<SidebarMenu>
{items.map((item) => (
<SidebarNavItem item={item} key={item.title} />
))}
</SidebarMenu>
</SidebarGroup>
);
}
function SidebarNavItem({ item }) {
const [isOpen, setIsOpen] = useState(Boolean(item.isActive));
if (!item.items?.length) {
return (
<SidebarMenuItem>
<SidebarMenuButton
render={<a href={item.url} />}
tooltip={item.title}
>
<item.icon />
<span>{item.title}</span>
</SidebarMenuButton>
</SidebarMenuItem>
);
}
return (
<Collapsible
onOpenChange={(open) => setIsOpen(open)}
open={isOpen}
render={<SidebarMenuItem />}
>
<CollapsibleTrigger
render={<SidebarMenuButton tooltip={item.title} />}
>
<item.icon />
<span>{item.title}</span>
<ChevronRight
className={`ml-auto transition-transform ${isOpen ? "rotate-90" : ""}`}
/>
</CollapsibleTrigger>
<CollapsiblePanel>
<SidebarMenuSub>
{item.items.map((subItem) => (
<SidebarMenuSubItem key={subItem.title}>
<SidebarMenuSubButton render={<a href={subItem.url} />}>
<span>{subItem.title}</span>
</SidebarMenuSubButton>
</SidebarMenuSubItem>
))}
</SidebarMenuSub>
</CollapsiblePanel>
</Collapsible>
);
}Menu Actions
import {
Menu,
MenuContent,
MenuItem,
MenuSeparator,
MenuTrigger,
SidebarMenuAction,
} from "@tilt-legal/cubitt-components/primitives";
import { Dots, Folder, ShareRight, Trash2 } from "@tilt-legal/cubitt-icons/ui/outline";
<Menu>
<MenuTrigger render={<SidebarMenuAction showOnHover />}>
<Dots />
<span className="sr-only">More</span>
</MenuTrigger>
<MenuContent side="right" align="start" className="w-48">
<MenuItem>
<Folder />
<span>View Project</span>
</MenuItem>
<MenuItem>
<ShareRight />
<span>Share Project</span>
</MenuItem>
<MenuSeparator />
<MenuItem variant="destructive">
<Trash2 />
<span>Delete Project</span>
</MenuItem>
</MenuContent>
</Menu>