Skip to main content

Starwind UI v1.15 is now available! With new prose, sidebar, and more components

Sidebar

Sidebars are one of the most complex components to build. They are central to any application and often contain a lot of moving parts.

The Starwind Sidebar is composable, themeable, and customizable.

Info

The Starwind Sidebar is extremely similar to the shadcn/ui sidebar component.

Installation

Structure

A Sidebar component is composed of the following parts:

  • SidebarProvider - Handles collapsible state and keyboard shortcuts
  • Sidebar - The sidebar container
  • SidebarHeader and SidebarFooter - Sticky at the top and bottom of the sidebar
  • SidebarContent - Scrollable content area
  • SidebarGroup - Section within the SidebarContent
  • SidebarTrigger - Button to toggle the sidebar
Sidebar Structure

Usage

Basic Layout

Wrap your application with SidebarProvider and place Sidebar alongside your main content:

---
import {
Sidebar,
SidebarContent,
SidebarProvider,
SidebarTrigger,
} from "@/components/starwind/sidebar";
import { AppSidebar } from "@/components/app-sidebar";
---
<SidebarProvider>
<AppSidebar />
<main>
<SidebarTrigger />
<slot />
</main>
</SidebarProvider>

Creating a Sidebar Component

---
import {
Sidebar,
SidebarContent,
SidebarFooter,
SidebarGroup,
SidebarHeader,
} from "@/components/starwind/sidebar";
---
<Sidebar>
<SidebarHeader />
<SidebarContent>
<SidebarGroup />
<SidebarGroup />
</SidebarContent>
<SidebarFooter />
</Sidebar>

With Menu Items

Use SidebarMenu, SidebarMenuItem, and SidebarMenuButton to create navigation menus:

With Inset Variant

When using the inset variant, wrap your main content in SidebarInset:

---
import {
Sidebar,
SidebarInset,
SidebarProvider,
} from "@/components/starwind/sidebar";
---
<SidebarProvider>
<Sidebar variant="inset">
{/* Sidebar content */}
</Sidebar>
<SidebarInset>
<main>{/* Main content */}</main>
</SidebarInset>
</SidebarProvider>

API Reference

SidebarProvider

The root component that provides sidebar state and handles keyboard shortcuts.

PropTypeDefault
defaultOpenbooleantrue
keyboardShortcutstring"b"
classstring-
<SidebarProvider defaultOpen={true} keyboardShortcut="b">
{/* Sidebar and content */}
</SidebarProvider>

Additional Notes:

  • defaultOpen: Controls whether the sidebar starts expanded or collapsed
  • keyboardShortcut: The key used with Cmd (Mac) or Ctrl (Windows) to toggle the sidebar

Width

Control the sidebar width using CSS variables on SidebarProvider:

<SidebarProvider
style={{
"--sidebar-width": "20rem",
"--sidebar-width-icon": "4rem",
}}
>
<Sidebar />
</SidebarProvider>
VariableDefaultDescription
--sidebar-width18remWidth of the expanded sidebar
--sidebar-width-icon3.5remWidth when collapsed to icons

Keyboard Shortcut

The sidebar can be toggled using Cmd+B (Mac) or Ctrl+B (Windows). Customize this by setting the keyboardShortcut prop:

<SidebarProvider keyboardShortcut="s">
{/* Toggle with Cmd+S or Ctrl+S */}
</SidebarProvider>

Events

The provider dispatches the following custom events:

EventDescription
sidebar:changeFired when sidebar open state changes
sidebar:mobile-changeFired when mobile sidebar state changes

Listen for state changes:

<script>
const provider = document.querySelector('[data-slot="sidebar-provider"]');
provider?.addEventListener("sidebar:change", (e) => {
const { open, state } = e.detail;
console.log("Sidebar is now:", state);
});
</script>

The main sidebar container.

PropTypeDefault
side"left" | "right""left"
variant"sidebar" | "floating" | "inset""sidebar"
collapsible"offcanvas" | "icon" | "none""offcanvas"
classstring-
<Sidebar side="left" variant="sidebar" collapsible="offcanvas">
{/* Content */}
</Sidebar>

Additional Notes:

  • side: Which side of the viewport the sidebar appears on
  • variant: Visual style - sidebar (default), floating (with border/shadow), or inset (rounded, use with SidebarInset)
  • collapsible: How the sidebar collapses - offcanvas (slides out), icon (collapses to icons), or none (non-collapsible)

SidebarTrigger

A button that toggles the sidebar state.

PropTypeDefault
variantButton variant"ghost"
sizeButton size"icon-sm"
classstring-
<SidebarTrigger />

Use the icon slot for a custom icon:

<SidebarTrigger>
<MenuIcon slot="icon" />
</SidebarTrigger>

SidebarHeader

Sticky header at the top of the sidebar.

PropTypeDefault
classstring-
<Sidebar>
<SidebarHeader>
<h2>My App</h2>
</SidebarHeader>
{/* ... */}
</Sidebar>

SidebarFooter

Sticky footer at the bottom of the sidebar.

PropTypeDefault
classstring-
<Sidebar>
{/* ... */}
<SidebarFooter>
<UserMenu />
</SidebarFooter>
</Sidebar>

SidebarContent

Scrollable content area for sidebar groups.

PropTypeDefault
classstring-
<SidebarContent>
<SidebarGroup />
<SidebarGroup />
</SidebarContent>

SidebarGroup

A section within the sidebar content.

PropTypeDefault
classstring-
<SidebarGroup>
<SidebarGroupLabel>Navigation</SidebarGroupLabel>
<SidebarGroupContent>
<SidebarMenu>{/* Menu items */}</SidebarMenu>
</SidebarGroupContent>
</SidebarGroup>

SidebarGroupLabel

Label for a sidebar group.

PropTypeDefault
asChildbooleanfalse
classstring-
<SidebarGroupLabel>Application</SidebarGroupLabel>

SidebarGroupContent

Container for group content.

PropTypeDefault
classstring-

SidebarMenu

Container for menu items.

PropTypeDefault
classstring-
<SidebarMenu>
<SidebarMenuItem>{/* ... */}</SidebarMenuItem>
</SidebarMenu>

SidebarMenuItem

Individual menu item wrapper.

PropTypeDefault
classstring-

SidebarMenuButton

Interactive button or link within a menu item.

PropTypeDefault
hrefstring-
asChildbooleanfalse
isActivebooleanfalse
tooltipstring-
variant"default" | "outline""default"
size"default" | "sm" | "lg""default"
classstring-
<SidebarMenuButton href="/home" isActive={true} tooltip="Home">
<HomeIcon />
<span>Home</span>
</SidebarMenuButton>

Additional Notes:

  • href: When provided, renders as an anchor tag
  • isActive: Highlights the item as currently active
  • tooltip: Text shown in a tooltip when sidebar is collapsed to icons

SidebarMenuAction

Action button that appears alongside menu items.

PropTypeDefault
asChildbooleanfalse
showOnHoverbooleanfalse
classstring-
<SidebarMenuItem>
<SidebarMenuButton href="/projects">Projects</SidebarMenuButton>
<SidebarMenuAction showOnHover>
<PlusIcon />
</SidebarMenuAction>
</SidebarMenuItem>

SidebarMenuBadge

Badge displayed on a menu item.

PropTypeDefault
classstring-
<SidebarMenuItem>
<SidebarMenuButton>Inbox</SidebarMenuButton>
<SidebarMenuBadge>24</SidebarMenuBadge>
</SidebarMenuItem>

SidebarMenuSub

Container for submenu items.

PropTypeDefault
classstring-
<SidebarMenuItem>
<SidebarMenuButton>Settings</SidebarMenuButton>
<SidebarMenuSub>
<SidebarMenuSubItem>
<SidebarMenuSubButton href="/settings/profile">Profile</SidebarMenuSubButton>
</SidebarMenuSubItem>
</SidebarMenuSub>
</SidebarMenuItem>

SidebarMenuSubButton

Button for submenu items.

PropTypeDefault
hrefstring-
asChildbooleanfalse
isActivebooleanfalse
size"sm" | "md""md"
classstring-

SidebarMenuSkeleton

Loading skeleton for menu items.

PropTypeDefault
showIconbooleanfalse
classstring-
<SidebarMenu>
{Array.from({ length: 5 }).map(() => (
<SidebarMenuItem>
<SidebarMenuSkeleton showIcon />
</SidebarMenuItem>
))}
</SidebarMenu>

SidebarRail

A thin rail that allows toggling the sidebar by clicking or dragging.

PropTypeDefault
classstring-
<Sidebar>
{/* Content */}
<SidebarRail />
</Sidebar>

SidebarSeparator

Visual divider between sidebar sections.

PropTypeDefault
classstring-
<SidebarContent>
<SidebarGroup />
<SidebarSeparator />
<SidebarGroup />
</SidebarContent>

SidebarInset

Main content wrapper for use with the inset variant.

PropTypeDefault
classstring-
<SidebarProvider>
<Sidebar variant="inset" />
<SidebarInset>
<main>{/* Content */}</main>
</SidebarInset>
</SidebarProvider>

SidebarInput

Styled input for use in the sidebar (e.g., search).

PropTypeDefault
classstring-

Styling

Collapsible State Styling

Style elements based on the sidebar’s collapsible state:

<Sidebar collapsible="icon">
<SidebarContent>
<SidebarGroup class="group-data-[collapsible=icon]:hidden">
{/* Hidden when collapsed to icons */}
</SidebarGroup>
</SidebarContent>
</Sidebar>

Active State Styling

The SidebarMenuAction can be styled based on the menu button’s active state:

<SidebarMenuItem>
<SidebarMenuButton isActive />
<SidebarMenuAction class="peer-data-[active=true]/menu-button:opacity-100" />
</SidebarMenuItem>

Changelog

v1.0.0

  • Initial release with starwind v1.15.0