Sidebar
Structural layout primitive for sidebar navigation. Provides Header, Content, Footer, and Group slots.
Workspace
import { Sidebar } from '@/components/sidebar';
export const meta = {
layout: 'padded',
};
export default function SidebarPreview() {
return (
<div className="h-96 w-64 overflow-hidden rounded-lg border border-border bg-background">
<Sidebar>
<Sidebar.Header>
<div className="font-medium text-sm">Workspace</div>
</Sidebar.Header>
<Sidebar.Content>
<Sidebar.Group>
<div className="px-2 py-1 text-sm">Inbox</div>
<div className="px-2 py-1 text-sm">My Issues</div>
</Sidebar.Group>
<Sidebar.Group label="Workspace">
<div className="px-2 py-1 text-sm">Initiatives</div>
<div className="px-2 py-1 text-sm">Projects</div>
<div className="px-2 py-1 text-sm">Views</div>
</Sidebar.Group>
</Sidebar.Content>
<Sidebar.Footer>
<div className="text-foreground-secondary text-sm">
chris@playstack.co
</div>
</Sidebar.Footer>
</Sidebar>
</div>
);
} Dependencies
Source Code
import { Slot } from '@/components/slot';
import { cn } from '@/lib/utils/classnames';
interface SidebarProps extends React.ComponentPropsWithRef<'div'> {
asChild?: boolean;
}
const Sidebar = ({ ref, className, asChild, ...rest }: SidebarProps) => {
const Comp = asChild ? Slot : 'div';
return (
<Comp
ref={ref}
data-sidebar
className={cn('flex h-full flex-col', className)}
{...rest}
/>
);
};
const SidebarHeader = ({
ref,
className,
...rest
}: React.ComponentPropsWithRef<'div'>) => (
<div
ref={ref}
data-sidebar-header
className={cn('sticky top-0 shrink-0 p-3', className)}
{...rest}
/>
);
const SidebarContent = ({
ref,
className,
...rest
}: React.ComponentPropsWithRef<'div'>) => (
<div
ref={ref}
data-sidebar-content
className={cn('flex-1 overflow-y-auto', className)}
{...rest}
/>
);
const SidebarFooter = ({
ref,
className,
...rest
}: React.ComponentPropsWithRef<'div'>) => (
<div
ref={ref}
data-sidebar-footer
className={cn(
'sticky bottom-0 shrink-0 border-border border-t p-3',
className
)}
{...rest}
/>
);
interface SidebarGroupProps extends React.ComponentPropsWithRef<'div'> {
label?: React.ReactNode;
}
const SidebarGroup = ({
ref,
className,
label,
children,
...rest
}: SidebarGroupProps) => (
<div
ref={ref}
data-sidebar-group
className={cn('flex flex-col gap-1 py-2', className)}
{...rest}
>
{label ? (
<p className="px-2 py-1 font-medium text-foreground-secondary/70 text-xs uppercase tracking-wider">
{label}
</p>
) : null}
<div className="flex flex-col gap-0.5">{children}</div>
</div>
);
const CompoundSidebar = Object.assign(Sidebar, {
Header: SidebarHeader,
Content: SidebarContent,
Footer: SidebarFooter,
Group: SidebarGroup,
});
export type { SidebarGroupProps, SidebarProps };
export { CompoundSidebar as Sidebar }; Server component. No
'use client'— sidebar chrome layout compound; forwards props only.
Sidebar is a structural layout primitive for building sidebar navigation
regions. It is unstyled with respect to background — sit it inside
AppShell.Sidebar (which provides the background and border) and use the
Header / Content / Footer / Group slots to lay out workspace switchers, nav
groups, and user rows.
Anatomy
<Sidebar>
<Sidebar.Header>{workspaceSwitcher}</Sidebar.Header>
<Sidebar.Content>
<Sidebar.Group>{primaryNav}</Sidebar.Group>
<Sidebar.Group label="Workspace">{workspaceNav}</Sidebar.Group>
</Sidebar.Content>
<Sidebar.Footer>{userRow}</Sidebar.Footer>
</Sidebar>
API Reference
Sidebar
Extends the div element.
| Prop | Default | Type | Description |
|---|---|---|---|
asChild | false | boolean | Render as the provided child element. Use to swap the default `<div>` for a semantic `<aside>` landmark without forking the component. |
asChild
Sidebar renders a <div> by default so it can sit inside AppShell.Sidebar
(which already renders an <aside> landmark). When you use Sidebar
standalone — outside AppShell — pass asChild to swap the root for an
<aside> so the navigation region is exposed as a landmark to assistive
tech.
<Sidebar asChild>
<aside aria-label="Primary">
<Sidebar.Header>{workspaceSwitcher}</Sidebar.Header>
<Sidebar.Content>{nav}</Sidebar.Content>
</aside>
</Sidebar>
Previous
Settings Row
Next
Skeleton