# Sidebar 09

> Collapsible nested sidebars.

A shadcn/ui block from the [@herocn](https://herocn.dev/) registry, listed on [shadcn.exchange](https://shadcn.exchange/r/herocn/sidebar-09).

- Page, with a live preview: https://shadcn.exchange/r/herocn/sidebar-09
- Screenshot: https://abzjhwgwpdpz7ua5.public.blob.vercel-storage.com/shots/herocn/sidebar-09-light-36ef847386a6bb21.png
- Registry item: https://herocn.dev/r/sidebar-09.json
- Categories: sidebar, dashboard
- Listed: 2026-10-13, source last changed 2026-10-13

## Install

```bash
npx shadcn@latest add https://herocn.dev/r/sidebar-09.json
```

Run it in a project that has shadcn/ui set up. It adds the files below and installs what they depend on.

## Dependencies

- Registry items: `@herocn/sidebar`, `@herocn/breadcrumb`, `@herocn/separator`, `@herocn/collapsible`, `@herocn/dropdown-menu`, `@herocn/avatar`, `@herocn/switch`, `@herocn/label`

## Files

### `page.tsx`

```tsx
import { AppSidebar } from "@/components/app-sidebar";
import {
	Breadcrumb,
	BreadcrumbItem,
	BreadcrumbLink,
	BreadcrumbList,
	BreadcrumbPage,
	BreadcrumbSeparator,
} from "@/components/ui/breadcrumb";
import { Separator } from "@/components/ui/separator";
import {
	SidebarInset,
	SidebarProvider,
	SidebarTrigger,
} from "@/components/ui/sidebar";

export default function Page() {
	return (
		<SidebarProvider
			style={
				{
					"--sidebar-width": "350px",
				} as React.CSSProperties
			}
		>
			<AppSidebar />
			<SidebarInset>
				<header className="sticky top-0 flex shrink-0 items-center gap-2 border-b bg-background p-4">
					<SidebarTrigger className="-ml-1" />
					<Separator
						orientation="vertical"
						className="mr-2 data-vertical:h-4 data-vertical:self-auto"
					/>
					<Breadcrumb>
						<BreadcrumbList>
							<BreadcrumbItem className="hidden md:block">
								<BreadcrumbLink href="#">All Inboxes</BreadcrumbLink>
							</BreadcrumbItem>
							<BreadcrumbSeparator className="hidden md:block" />
							<BreadcrumbItem>
								<BreadcrumbPage>Inbox</BreadcrumbPage>
							</BreadcrumbItem>
						</BreadcrumbList>
					</Breadcrumb>
				</header>
				<div className="flex flex-1 flex-col gap-4 p-4">
					{Array.from({ length: 24 }).map((_, index) => (
						<div
							key={index}
							className="aspect-video h-12 w-full rounded-lg bg-muted/50"
						/>
					))}
				</div>
			</SidebarInset>
		</SidebarProvider>
	);
}
```

### `components/app-sidebar.tsx`

```tsx
"use client";

import {
	ArchiveXIcon,
	FileIcon,
	InboxIcon,
	SendIcon,
	TerminalIcon,
	Trash2Icon,
} from "lucide-react";

import * as React from "react";

import { NavUser } from "@/components/nav-user";
import { Label } from "@/components/ui/label";
import {
	Sidebar,
	SidebarContent,
	SidebarFooter,
	SidebarGroup,
	SidebarGroupContent,
	SidebarHeader,
	SidebarInput,
	SidebarMenu,
	SidebarMenuButton,
	SidebarMenuItem,
	useSidebar,
} from "@/components/ui/sidebar";
import { Switch } from "@/components/ui/switch";

// This is sample data
const data = {
	user: {
		name: "Maqed",
		email: "maqed@example.com",
		avatar: "https://github.com/maqed.png",
	},
	navMain: [
		{
			title: "Inbox",
			url: "#",
			icon: <InboxIcon />,
			isActive: true,
		},
		{
			title: "Drafts",
			url: "#",
			icon: <FileIcon />,
			isActive: false,
		},
		{
			title: "Sent",
			url: "#",
			icon: <SendIcon />,
			isActive: false,
		},
		{
			title: "Junk",
			url: "#",
			icon: <ArchiveXIcon />,
			isActive: false,
		},
		{
			title: "Trash",
			url: "#",
			icon: <Trash2Icon />,
			isActive: false,
		},
	],
	mails: [
		{
			name: "William Smith",
			email: "williamsmith@example.com",
			subject: "Meeting Tomorrow",
			date: "09:34 AM",
			teaser:
				"Hi team, just a reminder about our meeting tomorrow at 10 AM.\nPlease come prepared with your project updates.",
		},
		{
			name: "Alice Smith",
			email: "alicesmith@example.com",
			subject: "Re: Project Update",
			date: "Yesterday",
			teaser:
				"Thanks for the update. The progress looks great so far.\nLet's schedule a call to discuss the next steps.",
		},
		{
			name: "Bob Johnson",
			email: "bobjohnson@example.com",
			subject: "Weekend Plans",
			date: "2 days ago",
			teaser:
				"Hey everyone! I'm thinking of organizing a team outing this weekend.\nWould you be interested in a hiking trip or a beach day?",
		},
		{
			name: "Emily Davis",
			email: "emilydavis@example.com",
			subject: "Re: Question about Budget",
			date: "2 days ago",
			teaser:
				"I've reviewed the budget numbers you sent over.\nCan we set up a quick call to discuss some potential adjustments?",
		},
		{
			name: "Michael Wilson",
			email: "michaelwilson@example.com",
			subject: "Important Announcement",
			date: "1 week ago",
			teaser:
				"Please join us for an all-hands meeting this Friday at 3 PM.\nWe have some exciting news to share about the company's future.",
		},
		{
			name: "Sarah Brown",
			email: "sarahbrown@example.com",
			subject: "Re: Feedback on Proposal",
			date: "1 week ago",
			teaser:
				"Thank you for sending over the proposal. I've reviewed it and have some thoughts.\nCould we schedule a meeting to discuss my feedback in detail?",
		},
		{
			name: "David Lee",
			email: "davidlee@example.com",
			subject: "New Project Idea",
			date: "1 week ago",
			teaser:
				"I've been brainstorming and came up with an interesting project concept.\nDo you have time this week to discuss its potential impact and feasibility?",
		},
		{
			name: "Olivia Wilson",
			email: "oliviawilson@example.com",
			subject: "Vacation Plans",
			date: "1 week ago",
			teaser:
				"Just a heads up that I'll be taking a two-week vacation next month.\nI'll make sure all my projects are up to date before I leave.",
		},
		{
			name: "James Martin",
			email: "jamesmartin@example.com",
			subject: "Re: Conference Registration",
			date: "1 week ago",
			teaser:
				"I've completed the registration for the upcoming tech conference.\nLet me know if you need any additional information from my end.",
		},
		{
			name: "Sophia White",
			email: "sophiawhite@example.com",
			subject: "Team Dinner",
			date: "1 week ago",
			teaser:
				"To celebrate our recent project success, I'd like to organize a team dinner.\nAre you available next Friday evening? Please let me know your preferences.",
		},
	],
};
export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {
	// Note: I'm using state to show active item.
	// IRL you should use the url/router.
	const [activeItem, setActiveItem] = React.useState(data.navMain[0]);
	const [mails, setMails] = React.useState(data.mails);
	const { setOpen } = useSidebar();
	return (
		<Sidebar
			collapsible="icon"
			className="overflow-hidden *:data-[sidebar=sidebar]:flex-row"
			{...props}
		>
			{/* This is the first sidebar */}
			{/* We disable collapsible and adjust width to icon. */}
			{/* This will make the sidebar appear as icons. */}
			<Sidebar
				collapsible="none"
				className="w-[calc(var(--sidebar-width-icon)+1px)]! border-r"
			>
				<SidebarHeader>
					<SidebarMenu>
						<SidebarMenuItem>
							<SidebarMenuButton
								size="lg"
								className="md:h-8 md:p-0"
								render={<a href="#" />}
							>
								<div className="flex aspect-square size-8 items-center justify-center rounded-lg bg-sidebar-primary text-sidebar-primary-foreground">
									<TerminalIcon className="size-4" />
								</div>
								<div className="grid flex-1 text-left text-sm leading-tight">
									<span className="truncate font-medium">Acme Inc</span>
									<span className="truncate text-xs">Enterprise</span>
								</div>
							</SidebarMenuButton>
						</SidebarMenuItem>
					</SidebarMenu>
				</SidebarHeader>
				<SidebarContent>
					<SidebarGroup>
						<SidebarGroupContent className="px-1.5 md:px-0">
							<SidebarMenu>
								{data.navMain.map((item) => (
									<SidebarMenuItem key={item.title}>
										<SidebarMenuButton
											tooltip={{
												children: item.title,
												hidden: false,
											}}
											onClick={() => {
												setActiveItem(item);
												const mail = data.mails.sort(() => Math.random() - 0.5);
												setMails(
													mail.slice(
														0,
														Math.max(5, Math.floor(Math.random() * 10) + 1),
													),
												);
												setOpen(true);
											}}
											isActive={activeItem?.title === item.title}
											className="px-2.5 md:px-2"
										>
											{item.icon}
											<span>{item.title}</span>
										</SidebarMenuButton>
									</SidebarMenuItem>
								))}
							</SidebarMenu>
						</SidebarGroupContent>
					</SidebarGroup>
				</SidebarContent>
				<SidebarFooter>
					<NavUser user={data.user} />
				</SidebarFooter>
			</Sidebar>

			{/* This is the second sidebar */}
			{/* We disable collapsible and let it fill remaining space */}
			<Sidebar collapsible="none" className="hidden flex-1 md:flex">
				<SidebarHeader className="gap-3.5 border-b p-4">
					<div className="flex w-full items-center justify-between">
						<div className="font-medium text-base text-foreground">
							{activeItem?.title}
						</div>
						<Label className="flex items-center gap-2 text-sm">
							<span>Unreads</span>
							<Switch className="shadow-none" />
						</Label>
					</div>
					<SidebarInput placeholder="Type to search..." />
				</SidebarHeader>
				<SidebarContent>
					<SidebarGroup className="px-0">
						<SidebarGroupContent>
							{mails.map((mail) => (
								<a
									href="#"
									key={mail.email}
									className="flex flex-col items-start gap-2 whitespace-nowrap border-b p-4 text-sm leading-tight last:border-b-0 hover:bg-sidebar-accent hover:text-sidebar-accent-foreground"
								>
									<div className="flex w-full items-center gap-2">
										<span>{mail.name}</span>{" "}
										<span className="ml-auto text-xs">{mail.date}</span>
									</div>
									<span className="font-medium">{mail.subject}</span>
									<span className="line-clamp-2 w-[260px] whitespace-break-spaces text-xs">
										{mail.teaser}
									</span>
								</a>
							))}
						</SidebarGroupContent>
					</SidebarGroup>
				</SidebarContent>
			</Sidebar>
		</Sidebar>
	);
}
```

### `components/nav-user.tsx`

```tsx
"use client";

import {
	BadgeCheckIcon,
	BellIcon,
	ChevronsUpDownIcon,
	CreditCardIcon,
	LogOutIcon,
	SparklesIcon,
} from "lucide-react";

import {
	Avatar,
	AvatarFallback,
	AvatarImage,
} from "@/components/ui/avatar";
import {
	DropdownMenu,
	DropdownMenuContent,
	DropdownMenuGroup,
	DropdownMenuItem,
	DropdownMenuLabel,
	DropdownMenuSeparator,
	DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import {
	SidebarMenu,
	SidebarMenuButton,
	SidebarMenuItem,
	useSidebar,
} from "@/components/ui/sidebar";

export function NavUser({
	user,
}: {
	user: {
		name: string;
		email: string;
		avatar: string;
	};
}) {
	const { isMobile } = useSidebar();
	return (
		<SidebarMenu>
			<SidebarMenuItem>
				<DropdownMenu>
					<DropdownMenuTrigger
						render={
							<SidebarMenuButton
								size="lg"
								className="data-open:bg-sidebar-accent data-open:text-sidebar-accent-foreground md:h-8 md:p-0"
							/>
						}
					>
						<Avatar className="h-8 w-8 rounded-lg">
							<AvatarImage src={user.avatar} alt={user.name} />
							<AvatarFallback className="rounded-lg">CN</AvatarFallback>
						</Avatar>
						<div className="grid flex-1 text-left text-sm leading-tight">
							<span className="truncate font-medium">{user.name}</span>
							<span className="truncate text-xs">{user.email}</span>
						</div>
						<ChevronsUpDownIcon className="ml-auto size-4" />
					</DropdownMenuTrigger>
					<DropdownMenuContent
						className="min-w-56 rounded-lg"
						side={isMobile ? "bottom" : "right"}
						align="end"
						sideOffset={4}
					>
						<DropdownMenuLabel className="p-0 font-normal">
							<div className="flex items-center gap-2 px-1 py-1.5 text-left text-sm">
								<Avatar className="h-8 w-8 rounded-lg">
									<AvatarImage src={user.avatar} alt={user.name} />
									<AvatarFallback className="rounded-lg">CN</AvatarFallback>
								</Avatar>
								<div className="grid flex-1 text-left text-sm leading-tight">
									<span className="truncate font-medium">{user.name}</span>
									<span className="truncate text-xs">{user.email}</span>
								</div>
							</div>
						</DropdownMenuLabel>
						<DropdownMenuSeparator />
						<DropdownMenuGroup>
							<DropdownMenuItem>
								<SparklesIcon />
								Upgrade to Pro
							</DropdownMenuItem>
						</DropdownMenuGroup>
						<DropdownMenuSeparator />
						<DropdownMenuGroup>
							<DropdownMenuItem>
								<BadgeCheckIcon />
								Account
							</DropdownMenuItem>
							<DropdownMenuItem>
								<CreditCardIcon />
								Billing
							</DropdownMenuItem>
							<DropdownMenuItem>
								<BellIcon />
								Notifications
							</DropdownMenuItem>
						</DropdownMenuGroup>
						<DropdownMenuSeparator />
						<DropdownMenuItem>
							<LogOutIcon />
							Log out
						</DropdownMenuItem>
					</DropdownMenuContent>
				</DropdownMenu>
			</SidebarMenuItem>
		</SidebarMenu>
	);
}
```
