ZaidanHomeDocsComponentsBlocksChartsTypesetCreate

Command Palette

Search for a command to run...

GitHub
New
Sections
  • Introduction
  • Components
  • Blocks
  • Installation
  • Customization
  • Dark Mode
  • Typeset
  • Zaidan Skills
  • FAQ
  • Roadmap
  • Changelog
Installation
  • Astro
  • Manual
  • Solid Start
  • TanStack Router
  • TanStack Start
  • Vite
Blocks
  • Data Grid
  • Event Calendar
  • Filters
  • Gantt
  • Image Crop
  • Kanban
  • Message Scroller
  • Questionnaire
  • Sortable
Components
  • Accordion
  • Alert
  • Alert Dialog
  • Aspect Ratio
  • Attachment
  • Avatar
  • Badge
  • Breadcrumb
  • Bubble
  • Button
  • Button Group
  • Calendar
  • Card
  • Carousel
  • Chart
  • Checkbox
  • Collapsible
  • Combobox
  • Command
  • Context Menu
  • Dialog
  • Drawer
  • Dropdown Menu
  • Empty
  • Field
  • Hover Card
  • Input
  • Input Group
  • Input OTP
  • Item
  • Kbd
  • Label
  • Marker
  • Menubar
  • Message
  • Native Select
  • Navigation Menu
  • Pagination
  • Popover
  • Progress
  • Radio Group
  • Resizable
  • Scroll Area
  • Select
  • Separator
  • Sheet
  • Sidebar
  • Skeleton
  • Slider
  • Spinner
  • Switch
  • Table
  • Tabs
  • Textarea
  • Toast
  • Toggle
  • Toggle Group
  • Tooltip

Sidebar

A composable, themeable and customizable sidebar component.

Kobalte
Kobalte

Sidebar is a native SolidJS composition that provides desktop collapse, a mobile sheet, and a consistent set of navigation building blocks. Its mobile sheet uses Kobalte Dialog for modal focus management and keyboard behavior.

Platform
    • History
    • Starred
    • Settings
Projects
  • Design Engineering
  • Sales & Marketing
  • Travel
1
import type { LucideIcon } from "lucide-solid";
2
import {
3
AudioWaveform,
4
BadgeCheck,
5
Bell,
6
BookOpen,
7
Bot,
8
ChevronRight,
9
ChevronsUpDown,
10
Command,
11
CreditCard,
12
Folder,
13
Forward,
14
Frame,
15
GalleryVerticalEnd,
16
LogOut,
17
MapIcon,
18
MoreHorizontal,
19
PieChart,
20
Plus,
21
Settings2,
22
Sparkles,
23
SquareTerminal,
24
Trash2,
25
} from "lucide-solid";
26
import { createSignal, For, Show } from "solid-js";
27
import { Dynamic } from "solid-js/web";
28
import { Avatar, AvatarFallback, AvatarImage } from "~/components/ui/avatar";
29
import {
30
Collapsible,
31
CollapsibleContent,
32
CollapsibleTrigger,
33
} from "~/components/ui/collapsible";
34
import {
35
DropdownMenu,
36
DropdownMenuContent,
37
DropdownMenuGroup,
38
DropdownMenuItem,
39
DropdownMenuLabel,
40
DropdownMenuSeparator,
41
DropdownMenuShortcut,
42
DropdownMenuTrigger,
43
} from "~/components/ui/dropdown-menu";
44
import {
45
Sidebar,
46
SidebarContent,
47
SidebarFooter,
48
SidebarGroup,
49
SidebarGroupLabel,
50
SidebarHeader,
51
SidebarInset,
52
SidebarMenu,
53
SidebarMenuAction,
54
SidebarMenuButton,
55
SidebarMenuItem,
56
SidebarMenuSub,
57
SidebarMenuSubButton,
58
SidebarMenuSubItem,
59
type SidebarProps,
60
SidebarProvider,
61
SidebarRail,
62
SidebarTrigger,
63
useSidebar,
64
} from "~/components/ui/sidebar";
65
66
// This is sample data.
67
const data = {
68
user: {
69
name: "shadcn",
70
email: "m@example.com",
71
avatar: "https://github.com/shadcn.png",
72
},
73
teams: [
74
{
75
name: "Acme Inc",
76
logo: GalleryVerticalEnd,
77
plan: "Enterprise",
78
},
79
{
80
name: "Acme Corp.",
81
logo: AudioWaveform,
82
plan: "Startup",
83
},
84
{
85
name: "Evil Corp.",
86
logo: Command,
87
plan: "Free",
88
},
89
],
90
navMain: [
91
{
92
title: "Playground",
93
url: "#",
94
icon: SquareTerminal,
95
isActive: true,
96
items: [
97
{
98
title: "History",
99
url: "#",
100
},
101
{
102
title: "Starred",
103
url: "#",
104
},
105
{
106
title: "Settings",
107
url: "#",
108
},
109
],
110
},
111
{
112
title: "Models",
113
url: "#",
114
icon: Bot,
115
items: [
116
{
117
title: "Genesis",
118
url: "#",
119
},
120
{
121
title: "Explorer",
122
url: "#",
123
},
124
{
125
title: "Quantum",
126
url: "#",
127
},
128
],
129
},
130
{
131
title: "Documentation",
132
url: "#",
133
icon: BookOpen,
134
items: [
135
{
136
title: "Introduction",
137
url: "#",
138
},
139
{
140
title: "Get Started",
141
url: "#",
142
},
143
{
144
title: "Tutorials",
145
url: "#",
146
},
147
{
148
title: "Changelog",
149
url: "#",
150
},
151
],
152
},
153
{
154
title: "Settings",
155
url: "#",
156
icon: Settings2,
157
items: [
158
{
159
title: "General",
160
url: "#",
161
},
162
{
163
title: "Team",
164
url: "#",
165
},
166
{
167
title: "Billing",
168
url: "#",
169
},
170
{
171
title: "Limits",
172
url: "#",
173
},
174
],
175
},
176
],
177
projects: [
178
{
179
name: "Design Engineering",
180
url: "#",
181
icon: Frame,
182
},
183
{
184
name: "Sales & Marketing",
185
url: "#",
186
icon: PieChart,
187
},
188
{
189
name: "Travel",
190
url: "#",
191
icon: MapIcon,
192
},
193
],
194
};
195
196
function TeamSwitcher(props: {
197
teams: {
198
name: string;
199
logo: LucideIcon;
200
plan: string;
201
}[];
202
}) {
203
const { isMobile } = useSidebar();
204
const [activeTeam, setActiveTeam] = createSignal(props.teams[0]);
205
206
return (
207
<Show when={activeTeam()}>
208
{(team) => (
209
<SidebarMenu>
210
<SidebarMenuItem>
211
<DropdownMenu placement={isMobile() ? "bottom-start" : "right-start"}>
212
<DropdownMenuTrigger
213
as={SidebarMenuButton}
214
size="lg"
215
class="data-expanded:bg-sidebar-accent data-expanded:text-sidebar-accent-foreground"
216
>
217
<div class="flex aspect-square size-8 items-center justify-center rounded-lg bg-sidebar-primary text-sidebar-primary-foreground">
218
<Dynamic component={team().logo} class="size-4" />
219
</div>
220
<div class="grid flex-1 text-left text-sm leading-tight">
221
<span class="truncate font-medium">{team().name}</span>
222
<span class="truncate text-xs">{team().plan}</span>
223
</div>
224
<ChevronsUpDown class="ml-auto" />
225
</DropdownMenuTrigger>
226
<DropdownMenuContent class="w-(--kb-popper-anchor-width) min-w-56 rounded-lg">
227
<DropdownMenuGroup>
228
<DropdownMenuLabel class="text-muted-foreground text-xs">Teams</DropdownMenuLabel>
229
<For each={props.teams}>
230
{(item, index) => (
231
<DropdownMenuItem onClick={() => setActiveTeam(item)} class="gap-2 p-2">
232
<div class="flex size-6 items-center justify-center rounded-md border">
233
<item.logo class="size-3.5 shrink-0" />
234
</div>
235
{item.name}
236
<DropdownMenuShortcut>⌘{index() + 1}</DropdownMenuShortcut>
237
</DropdownMenuItem>
238
)}
239
</For>
240
</DropdownMenuGroup>
241
<DropdownMenuSeparator />
242
<DropdownMenuGroup>
243
<DropdownMenuItem class="gap-2 p-2">
244
<div class="flex size-6 items-center justify-center rounded-md border bg-transparent">
245
<Plus class="size-4" />
246
</div>
247
<div class="font-medium text-muted-foreground">Add team</div>
248
</DropdownMenuItem>
249
</DropdownMenuGroup>
250
</DropdownMenuContent>
251
</DropdownMenu>
252
</SidebarMenuItem>
253
</SidebarMenu>
254
)}
255
</Show>
256
);
257
}
258
259
function NavMain(props: {
260
items: {
261
title: string;
262
url: string;
263
icon?: LucideIcon;
264
isActive?: boolean;
265
items?: {
266
title: string;
267
url: string;
268
}[];
269
}[];
270
}) {
271
return (
272
<SidebarGroup>
273
<SidebarGroupLabel>Platform</SidebarGroupLabel>
274
<SidebarMenu>
275
<For each={props.items}>
276
{(item) => (
277
<Collapsible defaultOpen={item.isActive} class="group/collapsible">
278
<SidebarMenuItem>
279
<CollapsibleTrigger as={SidebarMenuButton} tooltip={item.title}>
280
<Show when={item.icon}>{(icon) => <Dynamic component={icon()} />}</Show>
281
<span>{item.title}</span>
282
<ChevronRight class="ml-auto transition-transform duration-200 group-data-[expanded]/collapsible:rotate-90" />
283
</CollapsibleTrigger>
284
<CollapsibleContent>
285
<SidebarMenuSub>
286
<For each={item.items}>
287
{(subItem) => (
288
<SidebarMenuSubItem>
289
<SidebarMenuSubButton href={subItem.url}>
290
<span>{subItem.title}</span>
291
</SidebarMenuSubButton>
292
</SidebarMenuSubItem>
293
)}
294
</For>
295
</SidebarMenuSub>
296
</CollapsibleContent>
297
</SidebarMenuItem>
298
</Collapsible>
299
)}
300
</For>
301
</SidebarMenu>
302
</SidebarGroup>
303
);
304
}
305
306
function NavProjects(props: {
307
projects: {
308
name: string;
309
url: string;
310
icon: LucideIcon;
311
}[];
312
}) {
313
const { isMobile } = useSidebar();
314
315
return (
316
<SidebarGroup class="group-data-[collapsible=icon]:hidden">
317
<SidebarGroupLabel>Projects</SidebarGroupLabel>
318
<SidebarMenu>
319
<For each={props.projects}>
320
{(item) => (
321
<SidebarMenuItem>
322
<SidebarMenuButton as="a" href={item.url}>
323
<item.icon />
324
<span>{item.name}</span>
325
</SidebarMenuButton>
326
<DropdownMenu placement={isMobile() ? "bottom-end" : "right-start"}>
327
<DropdownMenuTrigger as={SidebarMenuAction} showOnHover class="">
328
<MoreHorizontal />
329
<span class="sr-only">More</span>
330
</DropdownMenuTrigger>
331
<DropdownMenuContent class="w-48 rounded-lg">
332
<DropdownMenuItem>
333
<Folder class="text-muted-foreground" />
334
<span>View Project</span>
335
</DropdownMenuItem>
336
<DropdownMenuItem>
337
<Forward class="text-muted-foreground" />
338
<span>Share Project</span>
339
</DropdownMenuItem>
340
<DropdownMenuSeparator />
341
<DropdownMenuItem>
342
<Trash2 class="text-muted-foreground" />
343
<span>Delete Project</span>
344
</DropdownMenuItem>
345
</DropdownMenuContent>
346
</DropdownMenu>
347
</SidebarMenuItem>
348
)}
349
</For>
350
<SidebarMenuItem>
351
<SidebarMenuButton class="text-sidebar-foreground/70">
352
<MoreHorizontal class="text-sidebar-foreground/70" />
353
<span>More</span>
354
</SidebarMenuButton>
355
</SidebarMenuItem>
356
</SidebarMenu>
357
</SidebarGroup>
358
);
359
}
360
361
function NavUser(props: {
362
user: {
363
name: string;
364
email: string;
365
avatar: string;
366
};
367
}) {
368
const { isMobile } = useSidebar();
369
370
return (
371
<SidebarMenu>
372
<SidebarMenuItem>
373
<DropdownMenu placement={isMobile() ? "bottom-end" : "right-end"}>
374
<DropdownMenuTrigger
375
as={SidebarMenuButton}
376
size="lg"
377
class="data-expanded:bg-sidebar-accent data-expanded:text-sidebar-accent-foreground"
378
>
379
<Avatar class="h-8 w-8 rounded-lg">
380
<AvatarImage src={props.user.avatar} alt={props.user.name} />
381
<AvatarFallback class="rounded-lg">CN</AvatarFallback>
382
</Avatar>
383
<div class="grid flex-1 text-left text-sm leading-tight">
384
<span class="truncate font-medium">{props.user.name}</span>
385
<span class="truncate text-xs">{props.user.email}</span>
386
</div>
387
<ChevronsUpDown class="ml-auto size-4" />
388
</DropdownMenuTrigger>
389
<DropdownMenuContent class="w-(--kb-popper-anchor-width) min-w-56 rounded-lg">
390
<DropdownMenuGroup>
391
<DropdownMenuLabel class="p-0 font-normal">
392
<div class="flex items-center gap-2 px-1 py-1.5 text-left text-sm">
393
<Avatar class="h-8 w-8 rounded-lg">
394
<AvatarImage src={props.user.avatar} alt={props.user.name} />
395
<AvatarFallback class="rounded-lg">CN</AvatarFallback>
396
</Avatar>
397
<div class="grid flex-1 text-left text-sm leading-tight">
398
<span class="truncate font-medium">{props.user.name}</span>
399
<span class="truncate text-xs">{props.user.email}</span>
400
</div>
401
</div>
402
</DropdownMenuLabel>
403
</DropdownMenuGroup>
404
<DropdownMenuSeparator />
405
<DropdownMenuGroup>
406
<DropdownMenuItem>
407
<Sparkles />
408
Upgrade to Pro
409
</DropdownMenuItem>
410
</DropdownMenuGroup>
411
<DropdownMenuSeparator />
412
<DropdownMenuGroup>
413
<DropdownMenuItem>
414
<BadgeCheck />
415
Account
416
</DropdownMenuItem>
417
<DropdownMenuItem>
418
<CreditCard />
419
Billing
420
</DropdownMenuItem>
421
<DropdownMenuItem>
422
<Bell />
423
Notifications
424
</DropdownMenuItem>
425
</DropdownMenuGroup>
426
<DropdownMenuSeparator />
427
<DropdownMenuGroup>
428
<DropdownMenuItem>
429
<LogOut />
430
Log out
431
</DropdownMenuItem>
432
</DropdownMenuGroup>
433
</DropdownMenuContent>
434
</DropdownMenu>
435
</SidebarMenuItem>
436
</SidebarMenu>
437
);
438
}
439
440
export default function SidebarDemo(props: SidebarProps) {
441
return (
442
<SidebarProvider>
443
<Sidebar collapsible="icon" {...props}>
444
<SidebarHeader>
445
<TeamSwitcher teams={data.teams} />
446
</SidebarHeader>
447
<SidebarContent>
448
<NavMain items={data.navMain} />
449
<NavProjects projects={data.projects} />
450
</SidebarContent>
451
<SidebarFooter>
452
<NavUser user={data.user} />
453
</SidebarFooter>
454
<SidebarRail />
455
</Sidebar>
456
<SidebarInset>
457
<header class="flex h-16 shrink-0 items-center gap-2 transition-[width,height] ease-linear group-has-data-[collapsible=icon]/sidebar-wrapper:h-12">
458
<div class="flex items-center gap-2 px-4">
459
<SidebarTrigger class="-ml-1" />
460
</div>
461
</header>
462
</SidebarInset>
463
</SidebarProvider>
464
);
465
}

Installation

pnpm dlx shadcn@latest add @zaidan/sidebar
npx shadcn@latest add @zaidan/sidebar
yarn dlx shadcn@latest add @zaidan/sidebar
bunx --bun shadcn@latest add @zaidan/sidebar

Usage

1
import { SidebarProvider, SidebarTrigger } from "~/components/ui/sidebar";
2
import { AppSidebar } from "~/components/app-sidebar";
3
4
export default function Layout(props: { children: JSX.Element }) {
5
return (
6
<SidebarProvider>
7
<AppSidebar />
8
<main>
9
<SidebarTrigger />
10
{props.children}
11
</main>
12
</SidebarProvider>
13
);
14
}
1
import {
2
Sidebar,
3
SidebarContent,
4
SidebarFooter,
5
SidebarGroup,
6
SidebarHeader,
7
} from "~/components/ui/sidebar";
8
9
export function AppSidebar() {
10
return (
11
<Sidebar>
12
<SidebarHeader />
13
<SidebarContent>
14
<SidebarGroup />
15
<SidebarGroup />
16
</SidebarContent>
17
<SidebarFooter />
18
</Sidebar>
19
);
20
}

Composition

Use the following composition to build a Sidebar layout:

SidebarProvider
├── Sidebar
│ ├── SidebarHeader
│ ├── SidebarContent
│ │ └── SidebarGroup
│ │ ├── SidebarGroupLabel
│ │ ├── SidebarGroupAction
│ │ ├── SidebarGroupContent
│ │ └── SidebarMenu
│ │ └── SidebarMenuItem
│ │ ├── SidebarMenuButton
│ │ ├── SidebarMenuAction
│ │ ├── SidebarMenuBadge
│ │ └── SidebarMenuSub
│ ├── SidebarFooter
│ └── SidebarRail
├── SidebarInset
└── SidebarTrigger

Structure

  • SidebarProvider manages desktop and mobile open state.
  • Sidebar renders the responsive sidebar surface.
  • SidebarHeader and SidebarFooter hold persistent controls.
  • SidebarContent is the scrollable navigation region.
  • SidebarGroup organizes related navigation.
  • SidebarMenu and SidebarMenuItem build menus, actions, badges, and submenus.
  • SidebarRail toggles the sidebar from its edge.
  • SidebarInset wraps the primary content for the inset variant.
  • SidebarTrigger toggles the sidebar from anywhere within the provider.

SidebarProvider

Wrap the application in SidebarProvider before rendering Sidebar or SidebarTrigger.

NameTypeDescription
defaultOpenbooleanInitial desktop open state.
openbooleanControlled desktop open state.
onOpenChange(open: boolean) => voidCalled when desktop state changes.

Width

For a single sidebar, change the width constants in sidebar.tsx. For multiple sidebars, set CSS variables on the provider.

1
<SidebarProvider
2
style={{
3
"--sidebar-width": "20rem",
4
"--sidebar-width-mobile": "20rem",
5
}}
6
>
7
<Sidebar />
8
</SidebarProvider>

Keyboard Shortcut

Press ⌘B on macOS or Ctrl+B elsewhere to toggle the sidebar. The default shortcut key is b.

Sidebar

Sidebar renders the main sidebar panel.

PropertyTypeDescription
side"left" | "right"The physical side of the viewport.
variant"sidebar" | "floating" | "inset"The visual treatment.
collapsible"offcanvas" | "icon" | "none"Desktop collapse behavior.
collapsible valueDescription
offcanvasSlides the sidebar fully offscreen.
iconCollapses the sidebar to its icon rail.
noneLeaves the sidebar fixed and non-collapsible.

When using the inset variant, wrap the primary content in SidebarInset.

1
<SidebarProvider>
2
<Sidebar variant="inset" />
3
<SidebarInset>
4
<main>{children}</main>
5
</SidebarInset>
6
</SidebarProvider>

Variants

Every visual treatment is a prop on the single Sidebar component — there are no separate variant components.

Floating

Set variant="floating" for a card-like panel with rounded corners and padding from the window edges.

  • Documentationv1.0.0
  • Getting Started
    • Installation
    • Project Structure
  • Building Your Application
    • Routing
    • Data Fetching
    • Rendering
    • Caching
    • Styling
    • Optimizing
    • Configuring
    • Testing
    • Authentication
    • Deploying
    • Upgrading
    • Examples
  • API Reference
    • Components
    • File Conventions
    • Functions
    • next.config.js Options
    • CLI
    • Edge Runtime
  • Architecture
    • Accessibility
    • Fast Refresh
    • Next.js Compiler
    • Supported Browsers
    • Turbopack
  • Community
    • Contribution Guide
  1. Building Your Application
  2. Data Fetching
1
import { GalleryVerticalEnd } from "lucide-solid";
2
import type { JSX } from "solid-js";
3
import { For, Show } from "solid-js";
4
import {
5
Breadcrumb,
6
BreadcrumbItem,
7
BreadcrumbLink,
8
BreadcrumbList,
9
BreadcrumbPage,
10
BreadcrumbSeparator,
11
} from "~/components/ui/breadcrumb";
12
import { Separator } from "~/components/ui/separator";
13
import {
14
Sidebar,
15
SidebarContent,
16
SidebarGroup,
17
SidebarHeader,
18
SidebarInset,
19
SidebarMenu,
20
SidebarMenuButton,
21
SidebarMenuItem,
22
SidebarMenuSub,
23
SidebarMenuSubButton,
24
SidebarMenuSubItem,
25
SidebarProvider,
26
SidebarTrigger,
27
} from "~/components/ui/sidebar";
28
29
// Sample data
30
const data = {
31
navMain: [
32
{
33
title: "Getting Started",
34
url: "#",
35
items: [
36
{ title: "Installation", url: "#" },
37
{ title: "Project Structure", url: "#" },
38
],
39
},
40
{
41
title: "Building Your Application",
42
url: "#",
43
items: [
44
{ title: "Routing", url: "#" },
45
{ title: "Data Fetching", url: "#", isActive: true },
46
{ title: "Rendering", url: "#" },
47
{ title: "Caching", url: "#" },
48
{ title: "Styling", url: "#" },
49
{ title: "Optimizing", url: "#" },
50
{ title: "Configuring", url: "#" },
51
{ title: "Testing", url: "#" },
52
{ title: "Authentication", url: "#" },
53
{ title: "Deploying", url: "#" },
54
{ title: "Upgrading", url: "#" },
55
{ title: "Examples", url: "#" },
56
],
57
},
58
{
59
title: "API Reference",
60
url: "#",
61
items: [
62
{ title: "Components", url: "#" },
63
{ title: "File Conventions", url: "#" },
64
{ title: "Functions", url: "#" },
65
{ title: "next.config.js Options", url: "#" },
66
{ title: "CLI", url: "#" },
67
{ title: "Edge Runtime", url: "#" },
68
],
69
},
70
{
71
title: "Architecture",
72
url: "#",
73
items: [
74
{ title: "Accessibility", url: "#" },
75
{ title: "Fast Refresh", url: "#" },
76
{ title: "Next.js Compiler", url: "#" },
77
{ title: "Supported Browsers", url: "#" },
78
{ title: "Turbopack", url: "#" },
79
],
80
},
81
{
82
title: "Community",
83
url: "#",
84
items: [{ title: "Contribution Guide", url: "#" }],
85
},
86
],
87
};
88
89
export default function SidebarFloatingExample() {
90
return (
91
<SidebarProvider
92
style={
93
{
94
"--sidebar-width": "19rem",
95
} as JSX.CSSProperties
96
}
97
>
98
<Sidebar variant="floating">
99
<SidebarHeader>
100
<SidebarMenu>
101
<SidebarMenuItem>
102
<SidebarMenuButton size="lg" as="a" href="#">
103
<div class="flex aspect-square size-8 items-center justify-center rounded-lg bg-sidebar-primary text-sidebar-primary-foreground">
104
<GalleryVerticalEnd class="size-4" />
105
</div>
106
<div class="flex flex-col gap-0.5 leading-none">
107
<span class="font-medium">Documentation</span>
108
<span class="">v1.0.0</span>
109
</div>
110
</SidebarMenuButton>
111
</SidebarMenuItem>
112
</SidebarMenu>
113
</SidebarHeader>
114
<SidebarContent>
115
<SidebarGroup>
116
<SidebarMenu class="gap-2">
117
<For each={data.navMain}>
118
{(item) => (
119
<SidebarMenuItem>
120
<SidebarMenuButton as="a" href={item.url} class="font-medium">
121
{item.title}
122
</SidebarMenuButton>
123
<Show when={item.items?.length}>
124
<SidebarMenuSub class="ml-0 border-l-0 px-1.5">
125
<For each={item.items}>
126
{(subItem) => (
127
<SidebarMenuSubItem>
128
<SidebarMenuSubButton
129
as="a"
130
href={subItem.url}
131
isActive={subItem.isActive}
132
>
133
{subItem.title}
134
</SidebarMenuSubButton>
135
</SidebarMenuSubItem>
136
)}
137
</For>
138
</SidebarMenuSub>
139
</Show>
140
</SidebarMenuItem>
141
)}
142
</For>
143
</SidebarMenu>
144
</SidebarGroup>
145
</SidebarContent>
146
</Sidebar>
147
<SidebarInset>
148
<header class="flex h-16 shrink-0 items-center gap-2 px-4">
149
<SidebarTrigger class="-ml-1" />
150
<Separator orientation="vertical" class="mr-2 data-[orientation=vertical]:h-4" />
151
<Breadcrumb>
152
<BreadcrumbList>
153
<BreadcrumbItem class="hidden md:block">
154
<BreadcrumbLink href="#">Building Your Application</BreadcrumbLink>
155
</BreadcrumbItem>
156
<BreadcrumbSeparator class="hidden md:block" />
157
<BreadcrumbItem>
158
<BreadcrumbPage>Data Fetching</BreadcrumbPage>
159
</BreadcrumbItem>
160
</BreadcrumbList>
161
</Breadcrumb>
162
</header>
163
<div class="flex flex-1 flex-col gap-4 p-4 pt-0">
164
<div class="grid auto-rows-min gap-4 md:grid-cols-3">
165
<div class="aspect-video rounded-xl bg-muted/50" />
166
<div class="aspect-video rounded-xl bg-muted/50" />
167
<div class="aspect-video rounded-xl bg-muted/50" />
168
</div>
169
<div class="min-h-[100vh] flex-1 rounded-xl bg-muted/50 md:min-h-min" />
170
</div>
171
</SidebarInset>
172
</SidebarProvider>
173
);
174
}

Inset

Set variant="inset" and wrap the primary content in SidebarInset.

  1. Building Your Application
  2. Data Fetching
Table of Contents
  • Getting Started
    • Installation
    • Project Structure
  • Building Your Application
    • Routing
    • Data Fetching
    • Rendering
    • Caching
    • Styling
    • Optimizing
    • Configuring
    • Testing
    • Authentication
    • Deploying
    • Upgrading
    • Examples
  • API Reference
    • Components
    • File Conventions
    • Functions
    • next.config.js Options
    • CLI
    • Edge Runtime
  • Architecture
    • Accessibility
    • Fast Refresh
    • Next.js Compiler
    • Supported Browsers
    • Turbopack
  • Community
    • Contribution Guide
1
import { For, Show } from "solid-js";
2
import {
3
Breadcrumb,
4
BreadcrumbItem,
5
BreadcrumbLink,
6
BreadcrumbList,
7
BreadcrumbPage,
8
BreadcrumbSeparator,
9
} from "~/components/ui/breadcrumb";
10
import {
11
Sidebar,
12
SidebarContent,
13
SidebarGroup,
14
SidebarGroupContent,
15
SidebarGroupLabel,
16
SidebarInset,
17
SidebarMenu,
18
SidebarMenuButton,
19
SidebarMenuItem,
20
SidebarMenuSub,
21
SidebarMenuSubButton,
22
SidebarMenuSubItem,
23
SidebarProvider,
24
SidebarRail,
25
SidebarTrigger,
26
} from "~/components/ui/sidebar";
27
28
// Sample data
29
const data = {
30
navMain: [
31
{
32
title: "Getting Started",
33
url: "#",
34
items: [
35
{ title: "Installation", url: "#" },
36
{ title: "Project Structure", url: "#" },
37
],
38
},
39
{
40
title: "Building Your Application",
41
url: "#",
42
items: [
43
{ title: "Routing", url: "#" },
44
{ title: "Data Fetching", url: "#", isActive: true },
45
{ title: "Rendering", url: "#" },
46
{ title: "Caching", url: "#" },
47
{ title: "Styling", url: "#" },
48
{ title: "Optimizing", url: "#" },
49
{ title: "Configuring", url: "#" },
50
{ title: "Testing", url: "#" },
51
{ title: "Authentication", url: "#" },
52
{ title: "Deploying", url: "#" },
53
{ title: "Upgrading", url: "#" },
54
{ title: "Examples", url: "#" },
55
],
56
},
57
{
58
title: "API Reference",
59
url: "#",
60
items: [
61
{ title: "Components", url: "#" },
62
{ title: "File Conventions", url: "#" },
63
{ title: "Functions", url: "#" },
64
{ title: "next.config.js Options", url: "#" },
65
{ title: "CLI", url: "#" },
66
{ title: "Edge Runtime", url: "#" },
67
],
68
},
69
{
70
title: "Architecture",
71
url: "#",
72
items: [
73
{ title: "Accessibility", url: "#" },
74
{ title: "Fast Refresh", url: "#" },
75
{ title: "Next.js Compiler", url: "#" },
76
{ title: "Supported Browsers", url: "#" },
77
{ title: "Turbopack", url: "#" },
78
],
79
},
80
{
81
title: "Community",
82
url: "#",
83
items: [{ title: "Contribution Guide", url: "#" }],
84
},
85
],
86
};
87
88
export default function SidebarInsetExample() {
89
return (
90
<SidebarProvider>
91
<SidebarInset>
92
<header class="flex h-16 shrink-0 items-center gap-2 border-b px-4">
93
<Breadcrumb>
94
<BreadcrumbList>
95
<BreadcrumbItem class="hidden md:block">
96
<BreadcrumbLink href="#">Building Your Application</BreadcrumbLink>
97
</BreadcrumbItem>
98
<BreadcrumbSeparator class="hidden md:block" />
99
<BreadcrumbItem>
100
<BreadcrumbPage>Data Fetching</BreadcrumbPage>
101
</BreadcrumbItem>
102
</BreadcrumbList>
103
</Breadcrumb>
104
<SidebarTrigger class="-mr-1 ml-auto rotate-180" />
105
</header>
106
<div class="flex flex-1 flex-col gap-4 p-4">
107
<div class="grid auto-rows-min gap-4 md:grid-cols-3">
108
<div class="aspect-video rounded-xl bg-muted/50" />
109
<div class="aspect-video rounded-xl bg-muted/50" />
110
<div class="aspect-video rounded-xl bg-muted/50" />
111
</div>
112
<div class="min-h-[100vh] flex-1 rounded-xl bg-muted/50 md:min-h-min" />
113
</div>
114
</SidebarInset>
115
<Sidebar variant="inset" side="right">
116
<SidebarContent>
117
<SidebarGroup>
118
<SidebarGroupLabel>Table of Contents</SidebarGroupLabel>
119
<SidebarGroupContent>
120
<SidebarMenu>
121
<For each={data.navMain}>
122
{(item) => (
123
<SidebarMenuItem>
124
<SidebarMenuButton as="a" href={item.url} class="font-medium">
125
{item.title}
126
</SidebarMenuButton>
127
<Show when={item.items?.length}>
128
<SidebarMenuSub>
129
<For each={item.items}>
130
{(subItem) => (
131
<SidebarMenuSubItem>
132
<SidebarMenuSubButton
133
as="a"
134
href={subItem.url}
135
isActive={subItem.isActive}
136
>
137
{subItem.title}
138
</SidebarMenuSubButton>
139
</SidebarMenuSubItem>
140
)}
141
</For>
142
</SidebarMenuSub>
143
</Show>
144
</SidebarMenuItem>
145
)}
146
</For>
147
</SidebarMenu>
148
</SidebarGroupContent>
149
</SidebarGroup>
150
</SidebarContent>
151
<SidebarRail />
152
</Sidebar>
153
</SidebarProvider>
154
);
155
}

Icon collapse

Set collapsible="icon" to collapse the sidebar to its icon rail instead of hiding it.

Platform
    • History
    • Starred
    • Settings
Projects
  • Design Engineering
  • Sales & Marketing
  • Travel
  1. Building Your Application
  2. Data Fetching
1
import {
2
AudioWaveform,
3
BadgeCheck,
4
Bell,
5
BookOpen,
6
Bot,
7
ChevronRight,
8
ChevronsUpDown,
9
Command,
10
CreditCard,
11
Folder,
12
Forward,
13
Frame,
14
GalleryVerticalEnd,
15
LogOut,
16
Map as MapIcon,
17
MoreHorizontal,
18
PieChart,
19
Plus,
20
Settings2,
21
Sparkles,
22
SquareTerminal,
23
Trash2,
24
} from "lucide-solid";
25
import type { Component, ComponentProps } from "solid-js";
26
import { createSignal, For, Show } from "solid-js";
27
import { Avatar, AvatarFallback, AvatarImage } from "~/components/ui/avatar";
28
import {
29
Breadcrumb,
30
BreadcrumbItem,
31
BreadcrumbLink,
32
BreadcrumbList,
33
BreadcrumbPage,
34
BreadcrumbSeparator,
35
} from "~/components/ui/breadcrumb";
36
import {
37
Collapsible,
38
CollapsibleContent,
39
CollapsibleTrigger,
40
} from "~/components/ui/collapsible";
41
import {
42
DropdownMenu,
43
DropdownMenuContent,
44
DropdownMenuGroup,
45
DropdownMenuItem,
46
DropdownMenuLabel,
47
DropdownMenuSeparator,
48
DropdownMenuTrigger,
49
} from "~/components/ui/dropdown-menu";
50
import { Kbd } from "~/components/ui/kbd";
51
import { Separator } from "~/components/ui/separator";
52
import {
53
Sidebar,
54
SidebarContent,
55
SidebarFooter,
56
SidebarGroup,
57
SidebarGroupLabel,
58
SidebarHeader,
59
SidebarInset,
60
SidebarMenu,
61
SidebarMenuAction,
62
SidebarMenuButton,
63
SidebarMenuItem,
64
SidebarMenuSub,
65
SidebarMenuSubButton,
66
SidebarMenuSubItem,
67
SidebarProvider,
68
SidebarRail,
69
SidebarTrigger,
70
useSidebar,
71
} from "~/components/ui/sidebar";
72
73
// Sample data
74
const data = {
75
user: {
76
name: "shadcn",
77
email: "m@example.com",
78
avatar: "/avatars/shadcn.jpg",
79
},
80
teams: [
81
{
82
name: "Acme Inc",
83
logo: GalleryVerticalEnd,
84
plan: "Enterprise",
85
},
86
{
87
name: "Acme Corp.",
88
logo: AudioWaveform,
89
plan: "Startup",
90
},
91
{
92
name: "Evil Corp.",
93
logo: Command,
94
plan: "Free",
95
},
96
],
97
navMain: [
98
{
99
title: "Playground",
100
url: "#",
101
icon: SquareTerminal,
102
isActive: true,
103
items: [
104
{ title: "History", url: "#" },
105
{ title: "Starred", url: "#" },
106
{ title: "Settings", url: "#" },
107
],
108
},
109
{
110
title: "Models",
111
url: "#",
112
icon: Bot,
113
items: [
114
{ title: "Genesis", url: "#" },
115
{ title: "Explorer", url: "#" },
116
{ title: "Quantum", url: "#" },
117
],
118
},
119
{
120
title: "Documentation",
121
url: "#",
122
icon: BookOpen,
123
items: [
124
{ title: "Introduction", url: "#" },
125
{ title: "Get Started", url: "#" },
126
{ title: "Tutorials", url: "#" },
127
{ title: "Changelog", url: "#" },
128
],
129
},
130
{
131
title: "Settings",
132
url: "#",
133
icon: Settings2,
134
items: [
135
{ title: "General", url: "#" },
136
{ title: "Team", url: "#" },
137
{ title: "Billing", url: "#" },
138
{ title: "Limits", url: "#" },
139
],
140
},
141
],
142
projects: [
143
{ name: "Design Engineering", url: "#", icon: Frame },
144
{ name: "Sales & Marketing", url: "#", icon: PieChart },
145
{ name: "Travel", url: "#", icon: MapIcon },
146
],
147
};
148
149
// Team Switcher component
150
function TeamSwitcher(props: {
151
teams: { name: string; logo: Component<ComponentProps<"svg">>; plan: string }[];
152
}) {
153
const { isMobile } = useSidebar();
154
const [activeTeam, setActiveTeam] = createSignal(props.teams[0]);
155
156
return (
157
<Show when={activeTeam()} keyed>
158
{(team) => (
159
<SidebarMenu>
160
<SidebarMenuItem>
161
<DropdownMenu placement={isMobile() ? "bottom" : "right"}>
162
<DropdownMenuTrigger
163
as={SidebarMenuButton}
164
size="lg"
165
class="data-[expanded]:bg-sidebar-accent data-[expanded]:text-sidebar-accent-foreground"
166
>
167
<div class="flex aspect-square size-8 items-center justify-center rounded-lg bg-sidebar-primary text-sidebar-primary-foreground">
168
{team.logo({ class: "size-4" })}
169
</div>
170
<div class="grid flex-1 text-left text-sm leading-tight">
171
<span class="truncate font-medium">{team.name}</span>
172
<span class="truncate text-xs">{team.plan}</span>
173
</div>
174
<ChevronsUpDown class="ml-auto" />
175
</DropdownMenuTrigger>
176
<DropdownMenuContent class="w-(--kb-popper-anchor-width) min-w-56 rounded-lg">
177
<DropdownMenuLabel class="text-muted-foreground text-xs">Teams</DropdownMenuLabel>
178
<For each={props.teams}>
179
{(team, index) => (
180
<DropdownMenuItem onSelect={() => setActiveTeam(team)} class="gap-2 p-2">
181
<div class="flex size-6 items-center justify-center rounded-md border">
182
{team.logo({ class: "size-3.5 shrink-0" })}
183
</div>
184
{team.name}
185
<Kbd class="ml-auto">⌘{index() + 1}</Kbd>
186
</DropdownMenuItem>
187
)}
188
</For>
189
<DropdownMenuSeparator />
190
<DropdownMenuItem class="gap-2 p-2">
191
<div class="flex size-6 items-center justify-center rounded-md border bg-transparent">
192
<Plus class="size-4" />
193
</div>
194
<span class="font-medium text-muted-foreground">Add team</span>
195
</DropdownMenuItem>
196
</DropdownMenuContent>
197
</DropdownMenu>
198
</SidebarMenuItem>
199
</SidebarMenu>
200
)}
201
</Show>
202
);
203
}
204
205
// Nav Main component
206
function NavMain(props: {
207
items: {
208
title: string;
209
url: string;
210
icon?: Component<ComponentProps<"svg">>;
211
isActive?: boolean;
212
items?: { title: string; url: string }[];
213
}[];
214
}) {
215
return (
216
<SidebarGroup>
217
<SidebarGroupLabel>Platform</SidebarGroupLabel>
218
<SidebarMenu>
219
<For each={props.items}>
220
{(item) => (
221
<Collapsible defaultOpen={item.isActive} class="group/collapsible">
222
<SidebarMenuItem>
223
<CollapsibleTrigger as={SidebarMenuButton} tooltip={item.title}>
224
<Show when={item.icon} keyed>
225
{(Icon) => <Icon />}
226
</Show>
227
<span>{item.title}</span>
228
<ChevronRight class="ml-auto transition-transform duration-200 group-data-[expanded]/collapsible:rotate-90" />
229
</CollapsibleTrigger>
230
<CollapsibleContent>
231
<SidebarMenuSub>
232
<For each={item.items}>
233
{(subItem) => (
234
<SidebarMenuSubItem>
235
<SidebarMenuSubButton as="a" href={subItem.url}>
236
<span>{subItem.title}</span>
237
</SidebarMenuSubButton>
238
</SidebarMenuSubItem>
239
)}
240
</For>
241
</SidebarMenuSub>
242
</CollapsibleContent>
243
</SidebarMenuItem>
244
</Collapsible>
245
)}
246
</For>
247
</SidebarMenu>
248
</SidebarGroup>
249
);
250
}
251
252
// Nav Projects component
253
function NavProjects(props: {
254
projects: { name: string; url: string; icon: Component<ComponentProps<"svg">> }[];
255
}) {
256
const { isMobile } = useSidebar();
257
258
return (
259
<SidebarGroup class="group-data-[collapsible=icon]:hidden">
260
<SidebarGroupLabel>Projects</SidebarGroupLabel>
261
<SidebarMenu>
262
<For each={props.projects}>
263
{(item) => (
264
<SidebarMenuItem>
265
<SidebarMenuButton as="a" href={item.url}>
266
{item.icon({})}
267
<span>{item.name}</span>
268
</SidebarMenuButton>
269
<DropdownMenu placement={isMobile() ? "bottom-end" : "right-start"}>
270
<DropdownMenuTrigger as={SidebarMenuAction} showOnHover class="">
271
<MoreHorizontal />
272
<span class="sr-only">More</span>
273
</DropdownMenuTrigger>
274
<DropdownMenuContent class="w-48 rounded-lg">
275
<DropdownMenuItem>
276
<Folder class="text-muted-foreground" />
277
<span>View Project</span>
278
</DropdownMenuItem>
279
<DropdownMenuItem>
280
<Forward class="text-muted-foreground" />
281
<span>Share Project</span>
282
</DropdownMenuItem>
283
<DropdownMenuSeparator />
284
<DropdownMenuItem>
285
<Trash2 class="text-muted-foreground" />
286
<span>Delete Project</span>
287
</DropdownMenuItem>
288
</DropdownMenuContent>
289
</DropdownMenu>
290
</SidebarMenuItem>
291
)}
292
</For>
293
<SidebarMenuItem>
294
<SidebarMenuButton class="text-sidebar-foreground/70">
295
<MoreHorizontal class="text-sidebar-foreground/70" />
296
<span>More</span>
297
</SidebarMenuButton>
298
</SidebarMenuItem>
299
</SidebarMenu>
300
</SidebarGroup>
301
);
302
}
303
304
// Nav User component
305
function NavUser(props: { user: { name: string; email: string; avatar: string } }) {
306
const { isMobile } = useSidebar();
307
308
return (
309
<SidebarMenu>
310
<SidebarMenuItem>
311
<DropdownMenu placement={isMobile() ? "bottom-end" : "right-end"}>
312
<DropdownMenuTrigger
313
as={SidebarMenuButton}
314
size="lg"
315
class="data-[expanded]:bg-sidebar-accent data-[expanded]:text-sidebar-accent-foreground"
316
>
317
<Avatar class="h-8 w-8 rounded-lg">
318
<AvatarImage src={props.user.avatar} alt={props.user.name} />
319
<AvatarFallback class="rounded-lg">CN</AvatarFallback>
320
</Avatar>
321
<div class="grid flex-1 text-left text-sm leading-tight">
322
<span class="truncate font-medium">{props.user.name}</span>
323
<span class="truncate text-xs">{props.user.email}</span>
324
</div>
325
<ChevronsUpDown class="ml-auto size-4" />
326
</DropdownMenuTrigger>
327
<DropdownMenuContent class="w-(--kb-popper-anchor-width) min-w-56 rounded-lg">
328
<DropdownMenuLabel class="p-0 font-normal">
329
<div class="flex items-center gap-2 px-1 py-1.5 text-left text-sm">
330
<Avatar class="h-8 w-8 rounded-lg">
331
<AvatarImage src={props.user.avatar} alt={props.user.name} />
332
<AvatarFallback class="rounded-lg">CN</AvatarFallback>
333
</Avatar>
334
<div class="grid flex-1 text-left text-sm leading-tight">
335
<span class="truncate font-medium">{props.user.name}</span>
336
<span class="truncate text-xs">{props.user.email}</span>
337
</div>
338
</div>
339
</DropdownMenuLabel>
340
<DropdownMenuSeparator />
341
<DropdownMenuGroup>
342
<DropdownMenuItem>
343
<Sparkles />
344
Upgrade to Pro
345
</DropdownMenuItem>
346
</DropdownMenuGroup>
347
<DropdownMenuSeparator />
348
<DropdownMenuGroup>
349
<DropdownMenuItem>
350
<BadgeCheck />
351
Account
352
</DropdownMenuItem>
353
<DropdownMenuItem>
354
<CreditCard />
355
Billing
356
</DropdownMenuItem>
357
<DropdownMenuItem>
358
<Bell />
359
Notifications
360
</DropdownMenuItem>
361
</DropdownMenuGroup>
362
<DropdownMenuSeparator />
363
<DropdownMenuItem>
364
<LogOut />
365
Log out
366
</DropdownMenuItem>
367
</DropdownMenuContent>
368
</DropdownMenu>
369
</SidebarMenuItem>
370
</SidebarMenu>
371
);
372
}
373
374
export default function SidebarIconExample() {
375
return (
376
<SidebarProvider>
377
<Sidebar collapsible="icon">
378
<SidebarHeader>
379
<TeamSwitcher teams={data.teams} />
380
</SidebarHeader>
381
<SidebarContent>
382
<NavMain items={data.navMain} />
383
<NavProjects projects={data.projects} />
384
</SidebarContent>
385
<SidebarFooter>
386
<NavUser user={data.user} />
387
</SidebarFooter>
388
<SidebarRail />
389
</Sidebar>
390
<SidebarInset>
391
<header class="flex h-16 shrink-0 items-center gap-2 transition-[width,height] ease-linear group-has-data-[collapsible=icon]/sidebar-wrapper:h-12">
392
<div class="flex items-center gap-2 px-4">
393
<SidebarTrigger class="-ml-1" />
394
<Separator orientation="vertical" class="mr-2 data-[orientation=vertical]:h-4" />
395
<Breadcrumb>
396
<BreadcrumbList>
397
<BreadcrumbItem class="hidden md:block">
398
<BreadcrumbLink href="#">Building Your Application</BreadcrumbLink>
399
</BreadcrumbItem>
400
<BreadcrumbSeparator class="hidden md:block" />
401
<BreadcrumbItem>
402
<BreadcrumbPage>Data Fetching</BreadcrumbPage>
403
</BreadcrumbItem>
404
</BreadcrumbList>
405
</Breadcrumb>
406
</div>
407
</header>
408
<div class="flex flex-1 flex-col gap-4 p-4 pt-0">
409
<div class="grid auto-rows-min gap-4 md:grid-cols-3">
410
<div class="aspect-video rounded-xl bg-muted/50" />
411
<div class="aspect-video rounded-xl bg-muted/50" />
412
<div class="aspect-video rounded-xl bg-muted/50" />
413
</div>
414
<div class="min-h-[100vh] flex-1 rounded-xl bg-muted/50 md:min-h-min" />
415
</div>
416
</SidebarInset>
417
</SidebarProvider>
418
);
419
}

useSidebar

Use useSidebar inside a provider to inspect and control state.

1
import { useSidebar } from "~/components/ui/sidebar";
2
3
export function CustomTrigger() {
4
const { open, toggleSidebar } = useSidebar();
5
6
return <button onClick={toggleSidebar}>{open() ? "Close" : "Open"} sidebar</button>;
7
}
PropertyTypeDescription
stateAccessor<"expanded" | "collapsed">Desktop visual state.
openAccessor<boolean>Desktop open state.
setOpen(open: boolean) => voidChanges desktop state.
openMobileAccessor<boolean>Mobile sheet state.
setOpenMobile(open: boolean) => voidChanges mobile sheet state.
isMobileAccessor<boolean>Whether the mobile presentation is active.
toggleSidebar() => voidToggles the appropriate presentation.

SidebarHeader

Use SidebarHeader for workspace switchers, branding, search, or other persistent top-level controls.

1
<SidebarHeader>
2
<SidebarMenu>
3
<SidebarMenuItem>
4
<SidebarMenuButton>
5
Select workspace
6
<ChevronDown class="ml-auto" />
7
</SidebarMenuButton>
8
</SidebarMenuItem>
9
</SidebarMenu>
10
</SidebarHeader>

SidebarFooter

Use SidebarFooter for user menus, settings, or persistent actions.

1
<SidebarFooter>
2
<SidebarMenu>
3
<SidebarMenuItem>
4
<SidebarMenuButton>
5
<User2 /> Username
6
</SidebarMenuButton>
7
</SidebarMenuItem>
8
</SidebarMenu>
9
</SidebarFooter>

SidebarContent

SidebarContent is the scrollable area between the header and footer. Add one or more groups inside it.

1
<SidebarContent>
2
<SidebarGroup />
3
<SidebarGroup />
4
</SidebarContent>

SidebarGroup

Use SidebarGroup to create a section. A group can contain a label, content, and an optional action.

1
<SidebarGroup>
2
<SidebarGroupLabel>Application</SidebarGroupLabel>
3
<SidebarGroupAction aria-label="Add project">
4
<Plus />
5
</SidebarGroupAction>
6
<SidebarGroupContent />
7
</SidebarGroup>

Wrap a group in Collapsible when its content should be independently expandable.

1
<Collapsible defaultOpen class="group/collapsible">
2
<SidebarGroup>
3
<CollapsibleTrigger as={SidebarGroupLabel}>
4
Help <ChevronDown class="ml-auto group-data-[expanded]/collapsible:rotate-180" />
5
</CollapsibleTrigger>
6
<CollapsibleContent>
7
<SidebarGroupContent />
8
</CollapsibleContent>
9
</SidebarGroup>
10
</Collapsible>

SidebarMenu

Use SidebarMenu and SidebarMenuItem for navigation links.

1
<SidebarMenu>
2
<For each={projects}>
3
{(project) => (
4
<SidebarMenuItem>
5
<SidebarMenuButton as="a" href={project.url}>
6
<project.icon />
7
<span>{project.name}</span>
8
</SidebarMenuButton>
9
</SidebarMenuItem>
10
)}
11
</For>
12
</SidebarMenu>

SidebarMenuButton

SidebarMenuButton renders a button by default and can render an anchor with as="a". Use isActive to mark the current item and tooltip to provide a collapsed-sidebar label.

1
<SidebarMenuButton as="a" href="#home" isActive tooltip="Home">
2
<Home />
3
<span>Home</span>
4
</SidebarMenuButton>

SidebarMenuAction

Use SidebarMenuAction for an action associated with a menu item. Set showOnHover when the action should stay visually quiet until its item is hovered or focused.

1
<SidebarMenuItem>
2
<SidebarMenuButton as="a" href="#home">
3
<Home />
4
<span>Home</span>
5
</SidebarMenuButton>
6
<SidebarMenuAction showOnHover aria-label="Add project">
7
<Plus />
8
</SidebarMenuAction>
9
</SidebarMenuItem>

SidebarMenuSub

Use SidebarMenuSub for nested navigation inside a menu item.

1
<SidebarMenuItem>
2
<SidebarMenuButton>Projects</SidebarMenuButton>
3
<SidebarMenuSub>
4
<SidebarMenuSubItem>
5
<SidebarMenuSubButton href="#design-system">Design system</SidebarMenuSubButton>
6
</SidebarMenuSubItem>
7
</SidebarMenuSub>
8
</SidebarMenuItem>

SidebarMenuBadge

Use SidebarMenuBadge to show a count or status in a menu item.

1
<SidebarMenuItem>
2
<SidebarMenuButton>Inbox</SidebarMenuButton>
3
<SidebarMenuBadge>24</SidebarMenuBadge>
4
</SidebarMenuItem>

SidebarMenuSkeleton

Use SidebarMenuSkeleton while navigation data is loading.

1
<SidebarMenu>
2
<For each={Array.from({ length: 5 })}>
3
{() => (
4
<SidebarMenuItem>
5
<SidebarMenuSkeleton showIcon />
6
</SidebarMenuItem>
7
)}
8
</For>
9
</SidebarMenu>

SidebarTrigger

Use SidebarTrigger anywhere within the provider to toggle the sidebar.

1
<SidebarTrigger />

SidebarRail

Use SidebarRail inside Sidebar to provide its edge toggle target.

1
<Sidebar>
2
<SidebarHeader />
3
<SidebarContent>
4
<SidebarGroup />
5
</SidebarContent>
6
<SidebarFooter />
7
<SidebarRail />
8
</Sidebar>

Controlled Sidebar

Control the desktop sidebar with a Solid signal.

1
const [open, setOpen] = createSignal(false);
2
3
<SidebarProvider open={open()} onOpenChange={setOpen}>
4
<Sidebar />
5
</SidebarProvider>;

Theming

The sidebar reads the sidebar semantic tokens from the active Zaidan style. Override them with your style variables when needed.

:root {
--sidebar: oklch(0.985 0 0);
--sidebar-foreground: oklch(0.145 0 0);
--sidebar-primary: oklch(0.205 0 0);
--sidebar-primary-foreground: oklch(0.985 0 0);
--sidebar-accent: oklch(0.97 0 0);
--sidebar-accent-foreground: oklch(0.205 0 0);
--sidebar-border: oklch(0.922 0 0);
--sidebar-ring: oklch(0.708 0 0);
}

Styling

Target the Sidebar data attributes to tailor collapsed and active states.

<Sidebar collapsible="icon">
<SidebarContent>
<SidebarGroup class="group-data-[collapsible=icon]:hidden" />
</SidebarContent>
</Sidebar>
<SidebarMenuItem>
<SidebarMenuButton />
<SidebarMenuAction class="peer-data-[active=true]/menu-button:opacity-100" />
</SidebarMenuItem>

API Reference

Sidebar's public API is native SolidJS composition. For mobile sheet primitive props, focus management, and keyboard behavior, see the Kobalte Dialog API reference.

On This Page

  • Installation
  • Usage
  • Composition
  • Structure
  • SidebarProvider
    • Width
    • Keyboard Shortcut
  • Sidebar
  • Variants
    • Floating
    • Inset
    • Icon collapse
  • useSidebar
  • SidebarHeader
  • SidebarFooter
  • SidebarContent
  • SidebarGroup
  • SidebarMenu
  • SidebarMenuButton
  • SidebarMenuAction
  • SidebarMenuSub
  • SidebarMenuBadge
  • SidebarMenuSkeleton
  • SidebarTrigger
  • SidebarRail
  • Controlled Sidebar
  • Theming
  • Styling
  • API Reference
Built by Kevin Abatan. The source code is available on GitHub.