suiss/ui
  • Docs
  • Components
  • Patterns
  • Interactions
  • Charts
  • Blocks
GitHubGet started
DocsComponentsPatternsInteractionsChartsBlocks
Components82
  • Overview
  • Accordion
  • Alert
  • Alert Dialog
  • Alert Sheet
  • Amount Input
  • Aspect Ratio
  • Attachment
  • Avatar
  • Badge
  • Bottom Bar
  • Breadcrumb
  • Bubble
  • Button
  • Button Group
  • Calendar
  • Card
  • Carousel
  • Chart
  • Checkbox
  • Chip
  • Collapsible
  • Combobox
  • Command
  • Context Menu
  • Dialog
  • Direction
  • Drawer
  • Dropdown Menu
  • Empty
  • FAB
  • Field
  • Fullscreen Menu
  • Haptics
  • Header
  • Hover Card
  • Icon
  • Input
  • Input Accessory Bar
  • Input Group
  • Input OTP
  • Item
  • Kbd
  • Keyboard Scroll View
  • Keypad
  • Label
  • Marker
  • Menubar
  • Message
  • Message Scroller
  • Native Select
  • Navigation Menu
  • Page Indicator
  • Pagination
  • Pin Pad
  • Popover
  • Progress
  • QR Scanner
  • Questionnaire
  • Radio Group
  • Resizable
  • Screen
  • Scroll Area
  • Select
  • Separator
  • Sheet
  • Sidebar
  • Signature Pad
  • Skeleton
  • Slider
  • Spinner
  • Switch
  • Tab Bar
  • Table
  • Tabs
  • Text
  • Textarea
  • Toast
  • Toggle
  • Toggle Group
  • Tooltip
  • Wheel Picker
  • Widget

suiss/ui · Component

Sidebar

A collapsible app sidebar for navigation, with icon, off-canvas and mobile sheet modes.

Sidebar is an open-source component from suiss/ui for React. The @esuiss/ui CLI copies its source into your project, so you own the code.

import {
  CalendarBlankIcon,
  CaretUpDownIcon,
  ChartBarIcon,
  DotsThreeIcon,
  FolderIcon,
  GearIcon,
  HouseIcon,
  LifebuoyIcon,
  PlusIcon,
  TrayIcon,
  UsersIcon,
} from "@phosphor-icons/react"
import { Separator } from "@/components/ui/separator"
import {
  Sidebar,
  SidebarContent,
  SidebarFooter,
  SidebarGroup,
  SidebarGroupAction,
  SidebarGroupContent,
  SidebarGroupLabel,
  SidebarHeader,
  SidebarInput,
  SidebarInset,
  SidebarMenu,
  SidebarMenuAction,
  SidebarMenuBadge,
  SidebarMenuButton,
  SidebarMenuItem,
  SidebarMenuSub,
  SidebarMenuSubButton,
  SidebarMenuSubItem,
  SidebarProvider,
  SidebarRail,
  SidebarSeparator,
  SidebarTrigger,
} from "@/components/ui/sidebar"

const mainNav = [
  {
    title: "Home",
    icon: (
      <HouseIcon />
    ),
    active: true,
  },
  {
    title: "Inbox",
    icon: (
      <TrayIcon />
    ),
    badge: "12",
  },
  {
    title: "Calendar",
    icon: (
      <CalendarBlankIcon />
    ),
  },
  {
    title: "Reports",
    icon: (
      <ChartBarIcon />
    ),
  },
]

const projects = ["Website redesign", "Mobile app", "Q3 planning"]

const workspaceNav = [
  {
    title: "Team",
    icon: (
      <UsersIcon />
    ),
  },
  {
    title: "Settings",
    icon: (
      <GearIcon />
    ),
  },
  {
    title: "Support",
    icon: (
      <LifebuoyIcon />
    ),
  },
]

type SidebarArgs = React.ComponentProps<typeof Sidebar>

function AppSidebar(props: SidebarArgs) {
  return (
    <Sidebar {...props}>
      <SidebarHeader>
        <SidebarMenu>
          <SidebarMenuItem>
            <SidebarMenuButton size="lg">
              <div className="bg-primary text-primary-foreground flex size-8 shrink-0 items-center justify-center rounded-xl text-sm font-semibold">
                A
              </div>
              <div className="grid flex-1 text-start leading-tight">
                <span className="truncate font-medium">Acme Inc.</span>
                <span className="text-foreground/70 truncate text-xs">
                  Pro plan
                </span>
              </div>
              <CaretUpDownIcon className="ms-auto" />
            </SidebarMenuButton>
          </SidebarMenuItem>
        </SidebarMenu>
        <SidebarInput placeholder="Search" aria-label="Search" />
      </SidebarHeader>
      <SidebarContent>
        <SidebarGroup>
          <SidebarGroupLabel>Platform</SidebarGroupLabel>
          <SidebarGroupContent>
            <SidebarMenu>
              {mainNav.map((item) => (
                <SidebarMenuItem key={item.title}>
                  <SidebarMenuButton
                    isActive={item.active}
                    tooltip={item.title}
                    render={<a href={`#${item.title.toLowerCase()}`} />}
                  >
                    {item.icon}
                    <span>{item.title}</span>
                  </SidebarMenuButton>
                  {item.badge && (
                    <SidebarMenuBadge>{item.badge}</SidebarMenuBadge>
                  )}
                </SidebarMenuItem>
              ))}
              <SidebarMenuItem>
                <SidebarMenuButton tooltip="Projects">
                  <FolderIcon />
                  <span>Projects</span>
                </SidebarMenuButton>
                <SidebarMenuAction showOnHover aria-label="More options">
                  <DotsThreeIcon />
                </SidebarMenuAction>
                <SidebarMenuSub>
                  {projects.map((project, index) => (
                    <SidebarMenuSubItem key={project}>
                      <SidebarMenuSubButton href="#" isActive={index === 0}>
                        <span>{project}</span>
                      </SidebarMenuSubButton>
                    </SidebarMenuSubItem>
                  ))}
                </SidebarMenuSub>
              </SidebarMenuItem>
            </SidebarMenu>
          </SidebarGroupContent>
        </SidebarGroup>
        <SidebarSeparator />
        <SidebarGroup>
          <SidebarGroupLabel>Workspace</SidebarGroupLabel>
          <SidebarGroupAction aria-label="Add member">
            <PlusIcon />
          </SidebarGroupAction>
          <SidebarGroupContent>
            <SidebarMenu>
              {workspaceNav.map((item) => (
                <SidebarMenuItem key={item.title}>
                  <SidebarMenuButton
                    tooltip={item.title}
                    render={<a href={`#${item.title.toLowerCase()}`} />}
                  >
                    {item.icon}
                    <span>{item.title}</span>
                  </SidebarMenuButton>
                </SidebarMenuItem>
              ))}
            </SidebarMenu>
          </SidebarGroupContent>
        </SidebarGroup>
      </SidebarContent>
      <SidebarFooter>
        <SidebarMenu>
          <SidebarMenuItem>
            <SidebarMenuButton size="lg">
              <div className="bg-muted flex size-8 shrink-0 items-center justify-center rounded-full text-xs font-medium">
                JL
              </div>
              <div className="grid flex-1 text-start leading-tight">
                <span className="truncate font-medium">Jordan Lee</span>
                <span className="text-foreground/70 truncate text-xs">
                  [email protected]
                </span>
              </div>
              <CaretUpDownIcon className="ms-auto" />
            </SidebarMenuButton>
          </SidebarMenuItem>
        </SidebarMenu>
      </SidebarFooter>
      <SidebarRail />
    </Sidebar>
  )
}

function AppShell({
  defaultOpen = true,
  sidebar,
  ...props
}: SidebarArgs & { defaultOpen?: boolean; sidebar?: React.ReactNode }) {
  return (
    <SidebarProvider defaultOpen={defaultOpen}>
      {sidebar ?? <AppSidebar {...props} />}
      <SidebarInset>
        <header className="flex h-14 shrink-0 items-center gap-2 border-b px-4">
          <SidebarTrigger className="-ms-1" />
          <Separator
            orientation="vertical"
            className="me-2 data-vertical:h-4 data-vertical:self-center"
          />
          <span className="text-muted-foreground text-sm">Platform</span>
          <span className="text-muted-foreground text-sm">/</span>
          <span className="text-sm font-medium">Home</span>
        </header>
        <div className="flex flex-1 flex-col gap-4 p-4">
          <div className="grid gap-4 md:grid-cols-3">
            {["Revenue", "Active users", "Open issues"].map((label) => (
              <div
                key={label}
                className="bg-muted flex aspect-video flex-col justify-end rounded-2xl p-4"
              >
                <span className="text-muted-foreground text-sm">{label}</span>
              </div>
            ))}
          </div>
          <div className="bg-muted min-h-64 flex-1 rounded-2xl" />
        </div>
      </SidebarInset>
    </SidebarProvider>
  )
}

export default function SidebarDemo() {
  return (
    <div className="h-[32rem] transform-gpu overflow-hidden [&_[data-slot=sidebar-container]]:h-full [&_[data-slot=sidebar-wrapper]]:min-h-full">
      <AppShell side="left" variant="sidebar" collapsible="icon" />
    </div>
  )
}

SidebarProvider holds the open state and wraps the whole layout. Inside it, Sidebar renders the panel and SidebarInset renders the main content beside it. The sidebar stacks SidebarHeader, a scrolling SidebarContent and SidebarFooter. Content is organized into SidebarGroup sections, each with a SidebarGroupLabel, an optional SidebarGroupAction and a SidebarGroupContent. Navigation lives in a SidebarMenu of SidebarMenuItem rows, each holding a SidebarMenuButton and optionally a SidebarMenuAction, SidebarMenuBadge or nested SidebarMenuSub.

SidebarTrigger and SidebarRail toggle the sidebar. On screens narrower than 48rem, the sidebar renders inside a Sheet instead. Use Sidebar for the main navigation of an app; for bottom navigation on small screens, consider TabBar.

Installation

CLI

$ pnpm dlx shadcn@latest add @esuiss/sidebar

Works in any project with a components.json. See Installation for the one-line registry setup. Or use the suiss/ui CLI:

$ pnpm dlx @esuiss/ui@latest add sidebar

Manual

  1. Install the dependencies and add the cn helper:
$ pnpm add @base-ui/react @phosphor-icons/react class-variance-authority
  1. Add the pieces it builds on: Button, Direction, Input, Separator, Sheet, Skeleton, Tooltip, use-mobile, use-platform.

  2. Copy the source into components/ui/sidebar.tsx:

  1. Update the import paths to match your project.

Usage

import { SidebarProvider, Sidebar, SidebarTrigger, SidebarRail, SidebarInset, SidebarInput, SidebarHeader, SidebarFooter, SidebarSeparator, SidebarContent, SidebarGroup, SidebarGroupLabel, SidebarGroupAction, SidebarGroupContent, SidebarMenu, SidebarMenuItem, SidebarMenuButton, SidebarMenuAction, SidebarMenuBadge, SidebarMenuSkeleton, SidebarMenuSub, SidebarMenuSubItem, SidebarMenuSubButton } 
<AppShell

Use defaultOpen on SidebarProvider for an uncontrolled sidebar, or open with onOpenChange to control it. Read and change state from any child with the useSidebar hook, which returns state, open, setOpen, openMobile, setOpenMobile, isMobile and toggleSidebar.

Set collapsible="icon" to shrink the sidebar to a rail of icons when collapsed, offcanvas to slide it out of view, or none to keep it fixed. Give each SidebarMenuButton a tooltip so its label stays available while collapsed to icons.

Use the render prop on SidebarMenuButton to render it as a link.

Set asChild on SidebarMenuButton and pass a link as the child to render it as a link.

Pass a render function to SidebarMenuButton that returns a link with the props it receives.

Examples

Floating

Uses the floating variant, a rounded panel with a shadow.

Inset

Uses the inset variant, which also raises the main content into a rounded card.

Collapsed

Starts collapsed to icons and expands from the rail.

Offcanvas

Slides the sidebar fully out of view when collapsed.

Right side

Places the sidebar on the right edge.

Loading

Shows SidebarMenuSkeleton placeholders while items load.

API Reference

01

SidebarProvider

Holds the open state, provides it through context and wraps the layout.

PropTypeDefaultDescription
defaultOpenbooleantrueSets whether the sidebar starts expanded when uncontrolled.
openboolean-Controls whether the sidebar is expanded.
onOpenChange(open: boolean) => void-Called with the new state when the sidebar expands or collapses.

Also accepts the props of React.ComponentProps<"div">.

02

Sidebar

The sidebar panel; a sheet on mobile.

PropTypeDefaultDescription
side"left" | "right""left"Places the sidebar on the left or right edge.
variant"sidebar" | "floating" | "inset""sidebar"Chooses a full-height sidebar, a rounded floating panel, or an inset layout.
collapsible"offcanvas" | "icon" | "none""offcanvas"Sets how the sidebar collapses: off canvas, to icons, or not at all.

Also accepts the props of React.ComponentProps<"div">.

03

SidebarTrigger

An icon button that toggles the sidebar.

Also accepts the props of React.ComponentProps<typeof Button>.

04

SidebarRail

A thin hit area along the sidebar's edge that toggles it on click.

Also accepts the props of React.ComponentProps<"button">.

05

SidebarInset

The main element for page content next to the sidebar.

Also accepts the props of React.ComponentProps<"main">.

06

SidebarInput

A compact Input styled for use in the sidebar.

Also accepts the props of React.ComponentProps<typeof Input>.

07

SidebarHeader

The top area, above the scrolling content.

Also accepts the props of React.ComponentProps<"div">.

08

SidebarFooter

The bottom area, below the scrolling content.

Also accepts the props of React.ComponentProps<"div">.

09

SidebarSeparator

A divider between sidebar sections.

Also accepts the props of React.ComponentProps<typeof Separator>.

10

SidebarContent

The scrolling region that holds the groups.

Also accepts the props of React.ComponentProps<"div">.

11

SidebarGroup

A section of related content.

Also accepts the props of React.ComponentProps<"div">.

12

SidebarGroupLabel

The title of a group; it fades out when collapsed to icons.

Also accepts the props of useRender.ComponentProps<"div">, React.ComponentProps<"div">.

13

SidebarGroupAction

A small button in the corner of a group, such as an add button.

Also accepts the props of useRender.ComponentProps<"button">, React.ComponentProps<"button">.

14

SidebarGroupContent

The body of a group.

Also accepts the props of React.ComponentProps<"div">.

15

SidebarMenu

A list of menu items.

Also accepts the props of React.ComponentProps<"ul">.

16

SidebarMenuItem

A list item that holds a menu button and its extras.

Also accepts the props of React.ComponentProps<"li">.

17

SidebarMenuButton

The clickable row for a destination or command.

PropTypeDefaultDescription
isActivebooleanfalseMarks the button as the current item.
tooltipstring | React.ComponentProps<typeof TooltipContent>-Text or TooltipContent props for a tooltip shown only while collapsed on desktop.
variant"default" | "outline""default"Uses a plain style or an outline style with a background and border.
size"default" | "sm" | "lg""default"Sets the row height: sm, default or lg.

Also accepts the props of useRender.ComponentProps<"button">, React.ComponentProps<"button">.

18

SidebarMenuAction

A small button at the end of a menu item, such as a more button.

PropTypeDefaultDescription
showOnHoverbooleanfalseOn desktop, hides the action until its item is hovered or focused.

Also accepts the props of useRender.ComponentProps<"button">, React.ComponentProps<"button">.

19

SidebarMenuBadge

A count or label shown at the end of a menu item.

Also accepts the props of React.ComponentProps<"div">.

20

SidebarMenuSkeleton

A loading placeholder shaped like a menu item.

PropTypeDefaultDescription
showIconbooleanfalseAdds a square placeholder for an icon.

Also accepts the props of React.ComponentProps<"div">.

21

SidebarMenuSub

A nested list of sub-items, indented with a leading line.

Also accepts the props of React.ComponentProps<"ul">.

22

SidebarMenuSubItem

A list item inside a sub-menu.

Also accepts the props of React.ComponentProps<"li">.

23

SidebarMenuSubButton

The clickable row of a sub-item, rendered as a link by default.

PropTypeDefaultDescription
size"sm" | "md""md"Sets the text size: sm or md.
isActivebooleanfalseMarks the sub-item as the current page.

Also accepts the props of useRender.ComponentProps<"a">, React.ComponentProps<"a">.

Accessibility

  • SidebarTrigger and SidebarRail are labelled Toggle Sidebar. The rail is removed from the tab order, so keep a SidebarTrigger in reach of keyboard users.
  • Press Command-B on Apple platforms, or Ctrl+B elsewhere, to toggle the sidebar.
  • On mobile, the sidebar is a dialog with a visually hidden title, Sidebar; Escape closes it.
  • Menu-button tooltips appear only while the sidebar is collapsed, so labels stay available when only icons show.

Notes

  • Every toggle writes the state to a sidebar_state cookie for 7 days. Read it on the server to set defaultOpen and avoid a flash on load.
  • Widths come from --sidebar-width (16rem) and --sidebar-width-icon (3rem), set on SidebarProvider; override them through its style.
  • The sidebar element exposes data-state (expanded or collapsed), data-collapsible, data-variant and data-side for styling. Menu buttons set data-active and data-size.
  • useSidebar throws if it's used outside a SidebarProvider.
  • The panel uses bg-sidebar; active items use bg-sidebar-accent with a text-sidebar-primary icon. Change the sidebar-* variables to style it apart from the page.
NextSignature PadPreviousSheet

On this page

  1. 01Installation
    • CLI
    • Manual
  2. 02Usage
  3. 03Examples
    • Floating
    • Inset
    • Collapsed
    • Offcanvas
    • Right side
    • Loading
  4. 04API Reference
    • SidebarProvider
    • Sidebar
    • SidebarTrigger
    • SidebarRail
    • SidebarInset
    • SidebarInput
    • SidebarHeader
    • SidebarFooter
    • SidebarSeparator
    • SidebarContent
    • SidebarGroup
    • SidebarGroupLabel
    • SidebarGroupAction
    • SidebarGroupContent
    • SidebarMenu
    • SidebarMenuItem
    • SidebarMenuButton
    • SidebarMenuAction
    • SidebarMenuBadge
    • SidebarMenuSkeleton
    • SidebarMenuSub
    • SidebarMenuSubItem
    • SidebarMenuSubButton
  5. 05Accessibility
  6. 06Notes
from
"@/components/ui/sidebar"
side
=
"left"
variant
=
"sidebar"
collapsible
=
"icon"
/>
components/ui/sidebar.tsx
"use client"

import { mergeProps } from "@base-ui/react/merge-props"
import { useRender } from "@base-ui/react/use-render"
import { SidebarIcon } from "@phosphor-icons/react"
import { cva, type VariantProps } from "class-variance-authority"
import * as React from "react"
import { Button } from "@/components/ui/button"
import { useDirection } from "@/components/ui/direction"
import { Input } from "@/components/ui/input"
import { Separator } from "@/components/ui/separator"
import {
  Sheet,
  SheetContent,
  SheetDescription,
  SheetHeader,
import {
  CalendarBlankIcon,
  CaretUpDownIcon,
  ChartBarIcon,
  DotsThreeIcon,
  FolderIcon,
  GearIcon,
  HouseIcon,
  LifebuoyIcon,
  PlusIcon,
  TrayIcon,
  UsersIcon,
} from "@phosphor-icons/react"
import { Separator } from "@/components/ui/separator"
import {
  Sidebar,
  SidebarContent,
  SidebarFooter,
  SidebarGroup,
  SidebarGroupAction,
  SidebarGroupContent,
  SidebarGroupLabel,
  SidebarHeader,
  SidebarInput,
  SidebarInset,
  SidebarMenu,
  SidebarMenuAction,
  SidebarMenuBadge,
  SidebarMenuButton,
  SidebarMenuItem,
  SidebarMenuSub,
  SidebarMenuSubButton,
  SidebarMenuSubItem,
  SidebarProvider,
  SidebarRail,
  SidebarSeparator,
  SidebarTrigger,
} from "@/components/ui/sidebar"

const mainNav = [
  {
    title: "Home",
    icon: (
      <HouseIcon />
    ),
    active: true,
  },
  {
    title: "Inbox",
    icon: (
      <TrayIcon />
    ),
    badge: "12",
  },
  {
    title: "Calendar",
    icon: (
      <CalendarBlankIcon />
    ),
  },
  {
    title: "Reports",
    icon: (
      <ChartBarIcon />
    ),
  },
]

const projects = ["Website redesign", "Mobile app", "Q3 planning"]

const workspaceNav = [
  {
    title: "Team",
    icon: (
      <UsersIcon />
    ),
  },
  {
    title: "Settings",
    icon: (
      <GearIcon />
    ),
  },
  {
    title: "Support",
    icon: (
      <LifebuoyIcon />
    ),
  },
]

type SidebarArgs = React.ComponentProps<typeof Sidebar>

function AppSidebar(props: SidebarArgs) {
  return (
    <Sidebar {...props}>
      <SidebarHeader>
        <SidebarMenu>
          <SidebarMenuItem>
            <SidebarMenuButton size="lg">
              <div className="bg-primary text-primary-foreground flex size-8 shrink-0 items-center justify-center rounded-xl text-sm font-semibold">
                A
              </div>
              <div className="grid flex-1 text-start leading-tight">
                <span className="truncate font-medium">Acme Inc.</span>
                <span className="text-foreground/70 truncate text-xs">
                  Pro plan
                </span>
              </div>
              <CaretUpDownIcon className="ms-auto" />
            </SidebarMenuButton>
          </SidebarMenuItem>
        </SidebarMenu>
        <SidebarInput placeholder="Search" aria-label="Search" />
      </SidebarHeader>
      <SidebarContent>
        <SidebarGroup>
          <SidebarGroupLabel>Platform</SidebarGroupLabel>
          <SidebarGroupContent>
            <SidebarMenu>
              {mainNav.map((item) => (
                <SidebarMenuItem key={item.title}>
                  <SidebarMenuButton
                    isActive={item.active}
                    tooltip={item.title}
                    render={<a href={`#${item.title.toLowerCase()}`} />}
                  >
                    {item.icon}
                    <span>{item.title}</span>
                  </SidebarMenuButton>
                  {item.badge && (
                    <SidebarMenuBadge>{item.badge}</SidebarMenuBadge>
                  )}
                </SidebarMenuItem>
              ))}
              <SidebarMenuItem>
                <SidebarMenuButton tooltip="Projects">
                  <FolderIcon />
                  <span>Projects</span>
                </SidebarMenuButton>
                <SidebarMenuAction showOnHover aria-label="More options">
                  <DotsThreeIcon />
                </SidebarMenuAction>
                <SidebarMenuSub>
                  {projects.map((project, index) => (
                    <SidebarMenuSubItem key={project}>
                      <SidebarMenuSubButton href="#" isActive={index === 0}>
                        <span>{project}</span>
                      </SidebarMenuSubButton>
                    </SidebarMenuSubItem>
                  ))}
                </SidebarMenuSub>
              </SidebarMenuItem>
            </SidebarMenu>
          </SidebarGroupContent>
        </SidebarGroup>
        <SidebarSeparator />
        <SidebarGroup>
          <SidebarGroupLabel>Workspace</SidebarGroupLabel>
          <SidebarGroupAction aria-label="Add member">
            <PlusIcon />
          </SidebarGroupAction>
          <SidebarGroupContent>
            <SidebarMenu>
              {workspaceNav.map((item) => (
                <SidebarMenuItem key={item.title}>
                  <SidebarMenuButton
                    tooltip={item.title}
                    render={<a href={`#${item.title.toLowerCase()}`} />}
                  >
                    {item.icon}
                    <span>{item.title}</span>
                  </SidebarMenuButton>
                </SidebarMenuItem>
              ))}
            </SidebarMenu>
          </SidebarGroupContent>
        </SidebarGroup>
      </SidebarContent>
      <SidebarFooter>
        <SidebarMenu>
          <SidebarMenuItem>
            <SidebarMenuButton size="lg">
              <div className="bg-muted flex size-8 shrink-0 items-center justify-center rounded-full text-xs font-medium">
                JL
              </div>
              <div className="grid flex-1 text-start leading-tight">
                <span className="truncate font-medium">Jordan Lee</span>
                <span className="text-foreground/70 truncate text-xs">
                  [email protected]
                </span>
              </div>
              <CaretUpDownIcon className="ms-auto" />
            </SidebarMenuButton>
          </SidebarMenuItem>
        </SidebarMenu>
      </SidebarFooter>
      <SidebarRail />
    </Sidebar>
  )
}

function AppShell({
  defaultOpen = true,
  sidebar,
  ...props
}: SidebarArgs & { defaultOpen?: boolean; sidebar?: React.ReactNode }) {
  return (
    <SidebarProvider defaultOpen={defaultOpen}>
      {sidebar ?? <AppSidebar {...props} />}
      <SidebarInset>
        <header className="flex h-14 shrink-0 items-center gap-2 border-b px-4">
          <SidebarTrigger className="-ms-1" />
          <Separator
            orientation="vertical"
            className="me-2 data-vertical:h-4 data-vertical:self-center"
          />
          <span className="text-muted-foreground text-sm">Platform</span>
          <span className="text-muted-foreground text-sm">/</span>
          <span className="text-sm font-medium">Home</span>
        </header>
        <div className="flex flex-1 flex-col gap-4 p-4">
          <div className="grid gap-4 md:grid-cols-3">
            {["Revenue", "Active users", "Open issues"].map((label) => (
              <div
                key={label}
                className="bg-muted flex aspect-video flex-col justify-end rounded-2xl p-4"
              >
                <span className="text-muted-foreground text-sm">{label}</span>
              </div>
            ))}
          </div>
          <div className="bg-muted min-h-64 flex-1 rounded-2xl" />
        </div>
      </SidebarInset>
    </SidebarProvider>
  )
}

export default function SidebarFloating() {
  return (
    <div className="h-[32rem] transform-gpu overflow-hidden [&_[data-slot=sidebar-container]]:h-full [&_[data-slot=sidebar-wrapper]]:min-h-full">
      <AppShell side="left" variant="floating" collapsible="icon" />
    </div>
  )
}
import {
  CalendarBlankIcon,
  CaretUpDownIcon,
  ChartBarIcon,
  DotsThreeIcon,
  FolderIcon,
  GearIcon,
  HouseIcon,
  LifebuoyIcon,
  PlusIcon,
  TrayIcon,
  UsersIcon,
} from "@phosphor-icons/react"
import { Separator } from "@/components/ui/separator"
import {
  Sidebar,
  SidebarContent,
  SidebarFooter,
  SidebarGroup,
  SidebarGroupAction,
  SidebarGroupContent,
  SidebarGroupLabel,
  SidebarHeader,
  SidebarInput,
  SidebarInset,
  SidebarMenu,
  SidebarMenuAction,
  SidebarMenuBadge,
  SidebarMenuButton,
  SidebarMenuItem,
  SidebarMenuSub,
  SidebarMenuSubButton,
  SidebarMenuSubItem,
  SidebarProvider,
  SidebarRail,
  SidebarSeparator,
  SidebarTrigger,
} from "@/components/ui/sidebar"

const mainNav = [
  {
    title: "Home",
    icon: (
      <HouseIcon />
    ),
    active: true,
  },
  {
    title: "Inbox",
    icon: (
      <TrayIcon />
    ),
    badge: "12",
  },
  {
    title: "Calendar",
    icon: (
      <CalendarBlankIcon />
    ),
  },
  {
    title: "Reports",
    icon: (
      <ChartBarIcon />
    ),
  },
]

const projects = ["Website redesign", "Mobile app", "Q3 planning"]

const workspaceNav = [
  {
    title: "Team",
    icon: (
      <UsersIcon />
    ),
  },
  {
    title: "Settings",
    icon: (
      <GearIcon />
    ),
  },
  {
    title: "Support",
    icon: (
      <LifebuoyIcon />
    ),
  },
]

type SidebarArgs = React.ComponentProps<typeof Sidebar>

function AppSidebar(props: SidebarArgs) {
  return (
    <Sidebar {...props}>
      <SidebarHeader>
        <SidebarMenu>
          <SidebarMenuItem>
            <SidebarMenuButton size="lg">
              <div className="bg-primary text-primary-foreground flex size-8 shrink-0 items-center justify-center rounded-xl text-sm font-semibold">
                A
              </div>
              <div className="grid flex-1 text-start leading-tight">
                <span className="truncate font-medium">Acme Inc.</span>
                <span className="text-foreground/70 truncate text-xs">
                  Pro plan
                </span>
              </div>
              <CaretUpDownIcon className="ms-auto" />
            </SidebarMenuButton>
          </SidebarMenuItem>
        </SidebarMenu>
        <SidebarInput placeholder="Search" aria-label="Search" />
      </SidebarHeader>
      <SidebarContent>
        <SidebarGroup>
          <SidebarGroupLabel>Platform</SidebarGroupLabel>
          <SidebarGroupContent>
            <SidebarMenu>
              {mainNav.map((item) => (
                <SidebarMenuItem key={item.title}>
                  <SidebarMenuButton
                    isActive={item.active}
                    tooltip={item.title}
                    render={<a href={`#${item.title.toLowerCase()}`} />}
                  >
                    {item.icon}
                    <span>{item.title}</span>
                  </SidebarMenuButton>
                  {item.badge && (
                    <SidebarMenuBadge>{item.badge}</SidebarMenuBadge>
                  )}
                </SidebarMenuItem>
              ))}
              <SidebarMenuItem>
                <SidebarMenuButton tooltip="Projects">
                  <FolderIcon />
                  <span>Projects</span>
                </SidebarMenuButton>
                <SidebarMenuAction showOnHover aria-label="More options">
                  <DotsThreeIcon />
                </SidebarMenuAction>
                <SidebarMenuSub>
                  {projects.map((project, index) => (
                    <SidebarMenuSubItem key={project}>
                      <SidebarMenuSubButton href="#" isActive={index === 0}>
                        <span>{project}</span>
                      </SidebarMenuSubButton>
                    </SidebarMenuSubItem>
                  ))}
                </SidebarMenuSub>
              </SidebarMenuItem>
            </SidebarMenu>
          </SidebarGroupContent>
        </SidebarGroup>
        <SidebarSeparator />
        <SidebarGroup>
          <SidebarGroupLabel>Workspace</SidebarGroupLabel>
          <SidebarGroupAction aria-label="Add member">
            <PlusIcon />
          </SidebarGroupAction>
          <SidebarGroupContent>
            <SidebarMenu>
              {workspaceNav.map((item) => (
                <SidebarMenuItem key={item.title}>
                  <SidebarMenuButton
                    tooltip={item.title}
                    render={<a href={`#${item.title.toLowerCase()}`} />}
                  >
                    {item.icon}
                    <span>{item.title}</span>
                  </SidebarMenuButton>
                </SidebarMenuItem>
              ))}
            </SidebarMenu>
          </SidebarGroupContent>
        </SidebarGroup>
      </SidebarContent>
      <SidebarFooter>
        <SidebarMenu>
          <SidebarMenuItem>
            <SidebarMenuButton size="lg">
              <div className="bg-muted flex size-8 shrink-0 items-center justify-center rounded-full text-xs font-medium">
                JL
              </div>
              <div className="grid flex-1 text-start leading-tight">
                <span className="truncate font-medium">Jordan Lee</span>
                <span className="text-foreground/70 truncate text-xs">
                  [email protected]
                </span>
              </div>
              <CaretUpDownIcon className="ms-auto" />
            </SidebarMenuButton>
          </SidebarMenuItem>
        </SidebarMenu>
      </SidebarFooter>
      <SidebarRail />
    </Sidebar>
  )
}

function AppShell({
  defaultOpen = true,
  sidebar,
  ...props
}: SidebarArgs & { defaultOpen?: boolean; sidebar?: React.ReactNode }) {
  return (
    <SidebarProvider defaultOpen={defaultOpen}>
      {sidebar ?? <AppSidebar {...props} />}
      <SidebarInset>
        <header className="flex h-14 shrink-0 items-center gap-2 border-b px-4">
          <SidebarTrigger className="-ms-1" />
          <Separator
            orientation="vertical"
            className="me-2 data-vertical:h-4 data-vertical:self-center"
          />
          <span className="text-muted-foreground text-sm">Platform</span>
          <span className="text-muted-foreground text-sm">/</span>
          <span className="text-sm font-medium">Home</span>
        </header>
        <div className="flex flex-1 flex-col gap-4 p-4">
          <div className="grid gap-4 md:grid-cols-3">
            {["Revenue", "Active users", "Open issues"].map((label) => (
              <div
                key={label}
                className="bg-muted flex aspect-video flex-col justify-end rounded-2xl p-4"
              >
                <span className="text-muted-foreground text-sm">{label}</span>
              </div>
            ))}
          </div>
          <div className="bg-muted min-h-64 flex-1 rounded-2xl" />
        </div>
      </SidebarInset>
    </SidebarProvider>
  )
}

export default function SidebarInsetExample() {
  return (
    <div className="h-[32rem] transform-gpu overflow-hidden [&_[data-slot=sidebar-container]]:h-full [&_[data-slot=sidebar-wrapper]]:min-h-full">
      <AppShell side="left" variant="inset" collapsible="icon" />
    </div>
  )
}
import {
  CalendarBlankIcon,
  CaretUpDownIcon,
  ChartBarIcon,
  DotsThreeIcon,
  FolderIcon,
  GearIcon,
  HouseIcon,
  LifebuoyIcon,
  PlusIcon,
  TrayIcon,
  UsersIcon,
} from "@phosphor-icons/react"
import { Separator } from "@/components/ui/separator"
import {
  Sidebar,
  SidebarContent,
  SidebarFooter,
  SidebarGroup,
  SidebarGroupAction,
  SidebarGroupContent,
  SidebarGroupLabel,
  SidebarHeader,
  SidebarInput,
  SidebarInset,
  SidebarMenu,
  SidebarMenuAction,
  SidebarMenuBadge,
  SidebarMenuButton,
  SidebarMenuItem,
  SidebarMenuSub,
  SidebarMenuSubButton,
  SidebarMenuSubItem,
  SidebarProvider,
  SidebarRail,
  SidebarSeparator,
  SidebarTrigger,
} from "@/components/ui/sidebar"

const mainNav = [
  {
    title: "Home",
    icon: (
      <HouseIcon />
    ),
    active: true,
  },
  {
    title: "Inbox",
    icon: (
      <TrayIcon />
    ),
    badge: "12",
  },
  {
    title: "Calendar",
    icon: (
      <CalendarBlankIcon />
    ),
  },
  {
    title: "Reports",
    icon: (
      <ChartBarIcon />
    ),
  },
]

const projects = ["Website redesign", "Mobile app", "Q3 planning"]

const workspaceNav = [
  {
    title: "Team",
    icon: (
      <UsersIcon />
    ),
  },
  {
    title: "Settings",
    icon: (
      <GearIcon />
    ),
  },
  {
    title: "Support",
    icon: (
      <LifebuoyIcon />
    ),
  },
]

type SidebarArgs = React.ComponentProps<typeof Sidebar>

function AppSidebar(props: SidebarArgs) {
  return (
    <Sidebar {...props}>
      <SidebarHeader>
        <SidebarMenu>
          <SidebarMenuItem>
            <SidebarMenuButton size="lg">
              <div className="bg-primary text-primary-foreground flex size-8 shrink-0 items-center justify-center rounded-xl text-sm font-semibold">
                A
              </div>
              <div className="grid flex-1 text-start leading-tight">
                <span className="truncate font-medium">Acme Inc.</span>
                <span className="text-foreground/70 truncate text-xs">
                  Pro plan
                </span>
              </div>
              <CaretUpDownIcon className="ms-auto" />
            </SidebarMenuButton>
          </SidebarMenuItem>
        </SidebarMenu>
        <SidebarInput placeholder="Search" aria-label="Search" />
      </SidebarHeader>
      <SidebarContent>
        <SidebarGroup>
          <SidebarGroupLabel>Platform</SidebarGroupLabel>
          <SidebarGroupContent>
            <SidebarMenu>
              {mainNav.map((item) => (
                <SidebarMenuItem key={item.title}>
                  <SidebarMenuButton
                    isActive={item.active}
                    tooltip={item.title}
                    render={<a href={`#${item.title.toLowerCase()}`} />}
                  >
                    {item.icon}
                    <span>{item.title}</span>
                  </SidebarMenuButton>
                  {item.badge && (
                    <SidebarMenuBadge>{item.badge}</SidebarMenuBadge>
                  )}
                </SidebarMenuItem>
              ))}
              <SidebarMenuItem>
                <SidebarMenuButton tooltip="Projects">
                  <FolderIcon />
                  <span>Projects</span>
                </SidebarMenuButton>
                <SidebarMenuAction showOnHover aria-label="More options">
                  <DotsThreeIcon />
                </SidebarMenuAction>
                <SidebarMenuSub>
                  {projects.map((project, index) => (
                    <SidebarMenuSubItem key={project}>
                      <SidebarMenuSubButton href="#" isActive={index === 0}>
                        <span>{project}</span>
                      </SidebarMenuSubButton>
                    </SidebarMenuSubItem>
                  ))}
                </SidebarMenuSub>
              </SidebarMenuItem>
            </SidebarMenu>
          </SidebarGroupContent>
        </SidebarGroup>
        <SidebarSeparator />
        <SidebarGroup>
          <SidebarGroupLabel>Workspace</SidebarGroupLabel>
          <SidebarGroupAction aria-label="Add member">
            <PlusIcon />
          </SidebarGroupAction>
          <SidebarGroupContent>
            <SidebarMenu>
              {workspaceNav.map((item) => (
                <SidebarMenuItem key={item.title}>
                  <SidebarMenuButton
                    tooltip={item.title}
                    render={<a href={`#${item.title.toLowerCase()}`} />}
                  >
                    {item.icon}
                    <span>{item.title}</span>
                  </SidebarMenuButton>
                </SidebarMenuItem>
              ))}
            </SidebarMenu>
          </SidebarGroupContent>
        </SidebarGroup>
      </SidebarContent>
      <SidebarFooter>
        <SidebarMenu>
          <SidebarMenuItem>
            <SidebarMenuButton size="lg">
              <div className="bg-muted flex size-8 shrink-0 items-center justify-center rounded-full text-xs font-medium">
                JL
              </div>
              <div className="grid flex-1 text-start leading-tight">
                <span className="truncate font-medium">Jordan Lee</span>
                <span className="text-foreground/70 truncate text-xs">
                  [email protected]
                </span>
              </div>
              <CaretUpDownIcon className="ms-auto" />
            </SidebarMenuButton>
          </SidebarMenuItem>
        </SidebarMenu>
      </SidebarFooter>
      <SidebarRail />
    </Sidebar>
  )
}

function AppShell({
  defaultOpen = true,
  sidebar,
  ...props
}: SidebarArgs & { defaultOpen?: boolean; sidebar?: React.ReactNode }) {
  return (
    <SidebarProvider defaultOpen={defaultOpen}>
      {sidebar ?? <AppSidebar {...props} />}
      <SidebarInset>
        <header className="flex h-14 shrink-0 items-center gap-2 border-b px-4">
          <SidebarTrigger className="-ms-1" />
          <Separator
            orientation="vertical"
            className="me-2 data-vertical:h-4 data-vertical:self-center"
          />
          <span className="text-muted-foreground text-sm">Platform</span>
          <span className="text-muted-foreground text-sm">/</span>
          <span className="text-sm font-medium">Home</span>
        </header>
        <div className="flex flex-1 flex-col gap-4 p-4">
          <div className="grid gap-4 md:grid-cols-3">
            {["Revenue", "Active users", "Open issues"].map((label) => (
              <div
                key={label}
                className="bg-muted flex aspect-video flex-col justify-end rounded-2xl p-4"
              >
                <span className="text-muted-foreground text-sm">{label}</span>
              </div>
            ))}
          </div>
          <div className="bg-muted min-h-64 flex-1 rounded-2xl" />
        </div>
      </SidebarInset>
    </SidebarProvider>
  )
}

export default function SidebarCollapsed() {
  return (
    <div className="h-[32rem] transform-gpu overflow-hidden [&_[data-slot=sidebar-container]]:h-full [&_[data-slot=sidebar-wrapper]]:min-h-full">
      <AppShell
        side="left"
        variant="sidebar"
        collapsible="icon"
        defaultOpen={false}
      />
    </div>
  )
}
import {
  CalendarBlankIcon,
  CaretUpDownIcon,
  ChartBarIcon,
  DotsThreeIcon,
  FolderIcon,
  GearIcon,
  HouseIcon,
  LifebuoyIcon,
  PlusIcon,
  TrayIcon,
  UsersIcon,
} from "@phosphor-icons/react"
import { Separator } from "@/components/ui/separator"
import {
  Sidebar,
  SidebarContent,
  SidebarFooter,
  SidebarGroup,
  SidebarGroupAction,
  SidebarGroupContent,
  SidebarGroupLabel,
  SidebarHeader,
  SidebarInput,
  SidebarInset,
  SidebarMenu,
  SidebarMenuAction,
  SidebarMenuBadge,
  SidebarMenuButton,
  SidebarMenuItem,
  SidebarMenuSub,
  SidebarMenuSubButton,
  SidebarMenuSubItem,
  SidebarProvider,
  SidebarRail,
  SidebarSeparator,
  SidebarTrigger,
} from "@/components/ui/sidebar"

const mainNav = [
  {
    title: "Home",
    icon: (
      <HouseIcon />
    ),
    active: true,
  },
  {
    title: "Inbox",
    icon: (
      <TrayIcon />
    ),
    badge: "12",
  },
  {
    title: "Calendar",
    icon: (
      <CalendarBlankIcon />
    ),
  },
  {
    title: "Reports",
    icon: (
      <ChartBarIcon />
    ),
  },
]

const projects = ["Website redesign", "Mobile app", "Q3 planning"]

const workspaceNav = [
  {
    title: "Team",
    icon: (
      <UsersIcon />
    ),
  },
  {
    title: "Settings",
    icon: (
      <GearIcon />
    ),
  },
  {
    title: "Support",
    icon: (
      <LifebuoyIcon />
    ),
  },
]

type SidebarArgs = React.ComponentProps<typeof Sidebar>

function AppSidebar(props: SidebarArgs) {
  return (
    <Sidebar {...props}>
      <SidebarHeader>
        <SidebarMenu>
          <SidebarMenuItem>
            <SidebarMenuButton size="lg">
              <div className="bg-primary text-primary-foreground flex size-8 shrink-0 items-center justify-center rounded-xl text-sm font-semibold">
                A
              </div>
              <div className="grid flex-1 text-start leading-tight">
                <span className="truncate font-medium">Acme Inc.</span>
                <span className="text-foreground/70 truncate text-xs">
                  Pro plan
                </span>
              </div>
              <CaretUpDownIcon className="ms-auto" />
            </SidebarMenuButton>
          </SidebarMenuItem>
        </SidebarMenu>
        <SidebarInput placeholder="Search" aria-label="Search" />
      </SidebarHeader>
      <SidebarContent>
        <SidebarGroup>
          <SidebarGroupLabel>Platform</SidebarGroupLabel>
          <SidebarGroupContent>
            <SidebarMenu>
              {mainNav.map((item) => (
                <SidebarMenuItem key={item.title}>
                  <SidebarMenuButton
                    isActive={item.active}
                    tooltip={item.title}
                    render={<a href={`#${item.title.toLowerCase()}`} />}
                  >
                    {item.icon}
                    <span>{item.title}</span>
                  </SidebarMenuButton>
                  {item.badge && (
                    <SidebarMenuBadge>{item.badge}</SidebarMenuBadge>
                  )}
                </SidebarMenuItem>
              ))}
              <SidebarMenuItem>
                <SidebarMenuButton tooltip="Projects">
                  <FolderIcon />
                  <span>Projects</span>
                </SidebarMenuButton>
                <SidebarMenuAction showOnHover aria-label="More options">
                  <DotsThreeIcon />
                </SidebarMenuAction>
                <SidebarMenuSub>
                  {projects.map((project, index) => (
                    <SidebarMenuSubItem key={project}>
                      <SidebarMenuSubButton href="#" isActive={index === 0}>
                        <span>{project}</span>
                      </SidebarMenuSubButton>
                    </SidebarMenuSubItem>
                  ))}
                </SidebarMenuSub>
              </SidebarMenuItem>
            </SidebarMenu>
          </SidebarGroupContent>
        </SidebarGroup>
        <SidebarSeparator />
        <SidebarGroup>
          <SidebarGroupLabel>Workspace</SidebarGroupLabel>
          <SidebarGroupAction aria-label="Add member">
            <PlusIcon />
          </SidebarGroupAction>
          <SidebarGroupContent>
            <SidebarMenu>
              {workspaceNav.map((item) => (
                <SidebarMenuItem key={item.title}>
                  <SidebarMenuButton
                    tooltip={item.title}
                    render={<a href={`#${item.title.toLowerCase()}`} />}
                  >
                    {item.icon}
                    <span>{item.title}</span>
                  </SidebarMenuButton>
                </SidebarMenuItem>
              ))}
            </SidebarMenu>
          </SidebarGroupContent>
        </SidebarGroup>
      </SidebarContent>
      <SidebarFooter>
        <SidebarMenu>
          <SidebarMenuItem>
            <SidebarMenuButton size="lg">
              <div className="bg-muted flex size-8 shrink-0 items-center justify-center rounded-full text-xs font-medium">
                JL
              </div>
              <div className="grid flex-1 text-start leading-tight">
                <span className="truncate font-medium">Jordan Lee</span>
                <span className="text-foreground/70 truncate text-xs">
                  [email protected]
                </span>
              </div>
              <CaretUpDownIcon className="ms-auto" />
            </SidebarMenuButton>
          </SidebarMenuItem>
        </SidebarMenu>
      </SidebarFooter>
      <SidebarRail />
    </Sidebar>
  )
}

function AppShell({
  defaultOpen = true,
  sidebar,
  ...props
}: SidebarArgs & { defaultOpen?: boolean; sidebar?: React.ReactNode }) {
  return (
    <SidebarProvider defaultOpen={defaultOpen}>
      {sidebar ?? <AppSidebar {...props} />}
      <SidebarInset>
        <header className="flex h-14 shrink-0 items-center gap-2 border-b px-4">
          <SidebarTrigger className="-ms-1" />
          <Separator
            orientation="vertical"
            className="me-2 data-vertical:h-4 data-vertical:self-center"
          />
          <span className="text-muted-foreground text-sm">Platform</span>
          <span className="text-muted-foreground text-sm">/</span>
          <span className="text-sm font-medium">Home</span>
        </header>
        <div className="flex flex-1 flex-col gap-4 p-4">
          <div className="grid gap-4 md:grid-cols-3">
            {["Revenue", "Active users", "Open issues"].map((label) => (
              <div
                key={label}
                className="bg-muted flex aspect-video flex-col justify-end rounded-2xl p-4"
              >
                <span className="text-muted-foreground text-sm">{label}</span>
              </div>
            ))}
          </div>
          <div className="bg-muted min-h-64 flex-1 rounded-2xl" />
        </div>
      </SidebarInset>
    </SidebarProvider>
  )
}

export default function SidebarOffcanvas() {
  return (
    <div className="h-[32rem] transform-gpu overflow-hidden [&_[data-slot=sidebar-container]]:h-full [&_[data-slot=sidebar-wrapper]]:min-h-full">
      <AppShell side="left" variant="sidebar" collapsible="offcanvas" />
    </div>
  )
}
import {
  CalendarBlankIcon,
  CaretUpDownIcon,
  ChartBarIcon,
  DotsThreeIcon,
  FolderIcon,
  GearIcon,
  HouseIcon,
  LifebuoyIcon,
  PlusIcon,
  TrayIcon,
  UsersIcon,
} from "@phosphor-icons/react"
import { Separator } from "@/components/ui/separator"
import {
  Sidebar,
  SidebarContent,
  SidebarFooter,
  SidebarGroup,
  SidebarGroupAction,
  SidebarGroupContent,
  SidebarGroupLabel,
  SidebarHeader,
  SidebarInput,
  SidebarInset,
  SidebarMenu,
  SidebarMenuAction,
  SidebarMenuBadge,
  SidebarMenuButton,
  SidebarMenuItem,
  SidebarMenuSub,
  SidebarMenuSubButton,
  SidebarMenuSubItem,
  SidebarProvider,
  SidebarRail,
  SidebarSeparator,
  SidebarTrigger,
} from "@/components/ui/sidebar"

const mainNav = [
  {
    title: "Home",
    icon: (
      <HouseIcon />
    ),
    active: true,
  },
  {
    title: "Inbox",
    icon: (
      <TrayIcon />
    ),
    badge: "12",
  },
  {
    title: "Calendar",
    icon: (
      <CalendarBlankIcon />
    ),
  },
  {
    title: "Reports",
    icon: (
      <ChartBarIcon />
    ),
  },
]

const projects = ["Website redesign", "Mobile app", "Q3 planning"]

const workspaceNav = [
  {
    title: "Team",
    icon: (
      <UsersIcon />
    ),
  },
  {
    title: "Settings",
    icon: (
      <GearIcon />
    ),
  },
  {
    title: "Support",
    icon: (
      <LifebuoyIcon />
    ),
  },
]

type SidebarArgs = React.ComponentProps<typeof Sidebar>

function AppSidebar(props: SidebarArgs) {
  return (
    <Sidebar {...props}>
      <SidebarHeader>
        <SidebarMenu>
          <SidebarMenuItem>
            <SidebarMenuButton size="lg">
              <div className="bg-primary text-primary-foreground flex size-8 shrink-0 items-center justify-center rounded-xl text-sm font-semibold">
                A
              </div>
              <div className="grid flex-1 text-start leading-tight">
                <span className="truncate font-medium">Acme Inc.</span>
                <span className="text-foreground/70 truncate text-xs">
                  Pro plan
                </span>
              </div>
              <CaretUpDownIcon className="ms-auto" />
            </SidebarMenuButton>
          </SidebarMenuItem>
        </SidebarMenu>
        <SidebarInput placeholder="Search" aria-label="Search" />
      </SidebarHeader>
      <SidebarContent>
        <SidebarGroup>
          <SidebarGroupLabel>Platform</SidebarGroupLabel>
          <SidebarGroupContent>
            <SidebarMenu>
              {mainNav.map((item) => (
                <SidebarMenuItem key={item.title}>
                  <SidebarMenuButton
                    isActive={item.active}
                    tooltip={item.title}
                    render={<a href={`#${item.title.toLowerCase()}`} />}
                  >
                    {item.icon}
                    <span>{item.title}</span>
                  </SidebarMenuButton>
                  {item.badge && (
                    <SidebarMenuBadge>{item.badge}</SidebarMenuBadge>
                  )}
                </SidebarMenuItem>
              ))}
              <SidebarMenuItem>
                <SidebarMenuButton tooltip="Projects">
                  <FolderIcon />
                  <span>Projects</span>
                </SidebarMenuButton>
                <SidebarMenuAction showOnHover aria-label="More options">
                  <DotsThreeIcon />
                </SidebarMenuAction>
                <SidebarMenuSub>
                  {projects.map((project, index) => (
                    <SidebarMenuSubItem key={project}>
                      <SidebarMenuSubButton href="#" isActive={index === 0}>
                        <span>{project}</span>
                      </SidebarMenuSubButton>
                    </SidebarMenuSubItem>
                  ))}
                </SidebarMenuSub>
              </SidebarMenuItem>
            </SidebarMenu>
          </SidebarGroupContent>
        </SidebarGroup>
        <SidebarSeparator />
        <SidebarGroup>
          <SidebarGroupLabel>Workspace</SidebarGroupLabel>
          <SidebarGroupAction aria-label="Add member">
            <PlusIcon />
          </SidebarGroupAction>
          <SidebarGroupContent>
            <SidebarMenu>
              {workspaceNav.map((item) => (
                <SidebarMenuItem key={item.title}>
                  <SidebarMenuButton
                    tooltip={item.title}
                    render={<a href={`#${item.title.toLowerCase()}`} />}
                  >
                    {item.icon}
                    <span>{item.title}</span>
                  </SidebarMenuButton>
                </SidebarMenuItem>
              ))}
            </SidebarMenu>
          </SidebarGroupContent>
        </SidebarGroup>
      </SidebarContent>
      <SidebarFooter>
        <SidebarMenu>
          <SidebarMenuItem>
            <SidebarMenuButton size="lg">
              <div className="bg-muted flex size-8 shrink-0 items-center justify-center rounded-full text-xs font-medium">
                JL
              </div>
              <div className="grid flex-1 text-start leading-tight">
                <span className="truncate font-medium">Jordan Lee</span>
                <span className="text-foreground/70 truncate text-xs">
                  [email protected]
                </span>
              </div>
              <CaretUpDownIcon className="ms-auto" />
            </SidebarMenuButton>
          </SidebarMenuItem>
        </SidebarMenu>
      </SidebarFooter>
      <SidebarRail />
    </Sidebar>
  )
}

function AppShell({
  defaultOpen = true,
  sidebar,
  ...props
}: SidebarArgs & { defaultOpen?: boolean; sidebar?: React.ReactNode }) {
  return (
    <SidebarProvider defaultOpen={defaultOpen}>
      {sidebar ?? <AppSidebar {...props} />}
      <SidebarInset>
        <header className="flex h-14 shrink-0 items-center gap-2 border-b px-4">
          <SidebarTrigger className="-ms-1" />
          <Separator
            orientation="vertical"
            className="me-2 data-vertical:h-4 data-vertical:self-center"
          />
          <span className="text-muted-foreground text-sm">Platform</span>
          <span className="text-muted-foreground text-sm">/</span>
          <span className="text-sm font-medium">Home</span>
        </header>
        <div className="flex flex-1 flex-col gap-4 p-4">
          <div className="grid gap-4 md:grid-cols-3">
            {["Revenue", "Active users", "Open issues"].map((label) => (
              <div
                key={label}
                className="bg-muted flex aspect-video flex-col justify-end rounded-2xl p-4"
              >
                <span className="text-muted-foreground text-sm">{label}</span>
              </div>
            ))}
          </div>
          <div className="bg-muted min-h-64 flex-1 rounded-2xl" />
        </div>
      </SidebarInset>
    </SidebarProvider>
  )
}

export default function SidebarRightSide() {
  return (
    <div className="h-[32rem] transform-gpu overflow-hidden [&_[data-slot=sidebar-container]]:h-full [&_[data-slot=sidebar-wrapper]]:min-h-full">
      <AppShell side="right" variant="sidebar" collapsible="icon" />
    </div>
  )
}
import {
  CalendarBlankIcon,
  CaretUpDownIcon,
  ChartBarIcon,
  DotsThreeIcon,
  FolderIcon,
  GearIcon,
  HouseIcon,
  LifebuoyIcon,
  PlusIcon,
  TrayIcon,
  UsersIcon,
} from "@phosphor-icons/react"
import { Separator } from "@/components/ui/separator"
import {
  Sidebar,
  SidebarContent,
  SidebarFooter,
  SidebarGroup,
  SidebarGroupAction,
  SidebarGroupContent,
  SidebarGroupLabel,
  SidebarHeader,
  SidebarInput,
  SidebarInset,
  SidebarMenu,
  SidebarMenuAction,
  SidebarMenuBadge,
  SidebarMenuButton,
  SidebarMenuItem,
  SidebarMenuSkeleton,
  SidebarMenuSub,
  SidebarMenuSubButton,
  SidebarMenuSubItem,
  SidebarProvider,
  SidebarRail,
  SidebarSeparator,
  SidebarTrigger,
} from "@/components/ui/sidebar"

const mainNav = [
  {
    title: "Home",
    icon: (
      <HouseIcon />
    ),
    active: true,
  },
  {
    title: "Inbox",
    icon: (
      <TrayIcon />
    ),
    badge: "12",
  },
  {
    title: "Calendar",
    icon: (
      <CalendarBlankIcon />
    ),
  },
  {
    title: "Reports",
    icon: (
      <ChartBarIcon />
    ),
  },
]

const projects = ["Website redesign", "Mobile app", "Q3 planning"]

const workspaceNav = [
  {
    title: "Team",
    icon: (
      <UsersIcon />
    ),
  },
  {
    title: "Settings",
    icon: (
      <GearIcon />
    ),
  },
  {
    title: "Support",
    icon: (
      <LifebuoyIcon />
    ),
  },
]

type SidebarArgs = React.ComponentProps<typeof Sidebar>

function AppSidebar(props: SidebarArgs) {
  return (
    <Sidebar {...props}>
      <SidebarHeader>
        <SidebarMenu>
          <SidebarMenuItem>
            <SidebarMenuButton size="lg">
              <div className="bg-primary text-primary-foreground flex size-8 shrink-0 items-center justify-center rounded-xl text-sm font-semibold">
                A
              </div>
              <div className="grid flex-1 text-start leading-tight">
                <span className="truncate font-medium">Acme Inc.</span>
                <span className="text-foreground/70 truncate text-xs">
                  Pro plan
                </span>
              </div>
              <CaretUpDownIcon className="ms-auto" />
            </SidebarMenuButton>
          </SidebarMenuItem>
        </SidebarMenu>
        <SidebarInput placeholder="Search" aria-label="Search" />
      </SidebarHeader>
      <SidebarContent>
        <SidebarGroup>
          <SidebarGroupLabel>Platform</SidebarGroupLabel>
          <SidebarGroupContent>
            <SidebarMenu>
              {mainNav.map((item) => (
                <SidebarMenuItem key={item.title}>
                  <SidebarMenuButton
                    isActive={item.active}
                    tooltip={item.title}
                    render={<a href={`#${item.title.toLowerCase()}`} />}
                  >
                    {item.icon}
                    <span>{item.title}</span>
                  </SidebarMenuButton>
                  {item.badge && (
                    <SidebarMenuBadge>{item.badge}</SidebarMenuBadge>
                  )}
                </SidebarMenuItem>
              ))}
              <SidebarMenuItem>
                <SidebarMenuButton tooltip="Projects">
                  <FolderIcon />
                  <span>Projects</span>
                </SidebarMenuButton>
                <SidebarMenuAction showOnHover aria-label="More options">
                  <DotsThreeIcon />
                </SidebarMenuAction>
                <SidebarMenuSub>
                  {projects.map((project, index) => (
                    <SidebarMenuSubItem key={project}>
                      <SidebarMenuSubButton href="#" isActive={index === 0}>
                        <span>{project}</span>
                      </SidebarMenuSubButton>
                    </SidebarMenuSubItem>
                  ))}
                </SidebarMenuSub>
              </SidebarMenuItem>
            </SidebarMenu>
          </SidebarGroupContent>
        </SidebarGroup>
        <SidebarSeparator />
        <SidebarGroup>
          <SidebarGroupLabel>Workspace</SidebarGroupLabel>
          <SidebarGroupAction aria-label="Add member">
            <PlusIcon />
          </SidebarGroupAction>
          <SidebarGroupContent>
            <SidebarMenu>
              {workspaceNav.map((item) => (
                <SidebarMenuItem key={item.title}>
                  <SidebarMenuButton
                    tooltip={item.title}
                    render={<a href={`#${item.title.toLowerCase()}`} />}
                  >
                    {item.icon}
                    <span>{item.title}</span>
                  </SidebarMenuButton>
                </SidebarMenuItem>
              ))}
            </SidebarMenu>
          </SidebarGroupContent>
        </SidebarGroup>
      </SidebarContent>
      <SidebarFooter>
        <SidebarMenu>
          <SidebarMenuItem>
            <SidebarMenuButton size="lg">
              <div className="bg-muted flex size-8 shrink-0 items-center justify-center rounded-full text-xs font-medium">
                JL
              </div>
              <div className="grid flex-1 text-start leading-tight">
                <span className="truncate font-medium">Jordan Lee</span>
                <span className="text-foreground/70 truncate text-xs">
                  [email protected]
                </span>
              </div>
              <CaretUpDownIcon className="ms-auto" />
            </SidebarMenuButton>
          </SidebarMenuItem>
        </SidebarMenu>
      </SidebarFooter>
      <SidebarRail />
    </Sidebar>
  )
}

function AppShell({
  defaultOpen = true,
  sidebar,
  ...props
}: SidebarArgs & { defaultOpen?: boolean; sidebar?: React.ReactNode }) {
  return (
    <SidebarProvider defaultOpen={defaultOpen}>
      {sidebar ?? <AppSidebar {...props} />}
      <SidebarInset>
        <header className="flex h-14 shrink-0 items-center gap-2 border-b px-4">
          <SidebarTrigger className="-ms-1" />
          <Separator
            orientation="vertical"
            className="me-2 data-vertical:h-4 data-vertical:self-center"
          />
          <span className="text-muted-foreground text-sm">Platform</span>
          <span className="text-muted-foreground text-sm">/</span>
          <span className="text-sm font-medium">Home</span>
        </header>
        <div className="flex flex-1 flex-col gap-4 p-4">
          <div className="grid gap-4 md:grid-cols-3">
            {["Revenue", "Active users", "Open issues"].map((label) => (
              <div
                key={label}
                className="bg-muted flex aspect-video flex-col justify-end rounded-2xl p-4"
              >
                <span className="text-muted-foreground text-sm">{label}</span>
              </div>
            ))}
          </div>
          <div className="bg-muted min-h-64 flex-1 rounded-2xl" />
        </div>
      </SidebarInset>
    </SidebarProvider>
  )
}

export default function SidebarLoading() {
  return (
    <div className="h-[32rem] transform-gpu overflow-hidden [&_[data-slot=sidebar-container]]:h-full [&_[data-slot=sidebar-wrapper]]:min-h-full">
      <AppShell
        sidebar={
          <Sidebar side="left" variant="sidebar" collapsible="icon">
            <SidebarHeader>
              <SidebarMenu>
                <SidebarMenuItem>
                  <SidebarMenuSkeleton showIcon />
                </SidebarMenuItem>
              </SidebarMenu>
            </SidebarHeader>
            <SidebarContent>
              <SidebarGroup>
                <SidebarGroupLabel>Platform</SidebarGroupLabel>
                <SidebarGroupContent>
                  <SidebarMenu>
                    {Array.from({ length: 6 }, (_, index) => (
                      <SidebarMenuItem key={index}>
                        <SidebarMenuSkeleton showIcon />
                      </SidebarMenuItem>
                    ))}
                  </SidebarMenu>
                </SidebarGroupContent>
              </SidebarGroup>
            </SidebarContent>
          </Sidebar>
        }
      />
    </div>
  )
}