Skip to content
Redpanda UI
Esc
↑↓navigate↵open⌘Jpreview
Made by malinskibeniamin
Edit on GitHub

Sidebar

A composable, themeable and customizable sidebar component. Created by Shadcn, animated by Animate UI, updated by malinskibeniamin.

Installation

bash
npx shadcn@latest add @redpanda/sidebar
bash
pnpm dlx shadcn@latest add @redpanda/sidebar
bash
yarn dlx shadcn@latest add @redpanda/sidebar
bash
bunx shadcn@latest add @redpanda/sidebar
bash
nubx shadcn@latest add @redpanda/sidebar
bash
aube dlx shadcn@latest add @redpanda/sidebar

Requires React and ReactDOM 19.2+ for useEffectEvent.

A sidebar that collapses to icons.

The sidebar examples share a demo account menu with an explicit name, email, avatar and fallback initials. The trigger and popup show the same identity. Its account actions are placeholders: connect them to your application when adapting an example. Installing a sidebar demo includes the shared helper; the Sidebar component itself remains composable.

On mobile, a collapsible Sidebar owns an edge-to-edge navigation dialog with the same sidebar tokens as desktop. Escape and outside presses dismiss it and restore focus to its opener. A real Close sidebar action is available to assistive technology; keyboard focus reveals it as a visible control. The dialog uses the configured portal container, and native Sidebar refs and attributes reach its popup.

collapsible="none" remains inline at every viewport width; it does not become a mobile dialog. The right-side inspector example deliberately uses that contract.

Sidebar owns its rail, separator and navigation-hover recipes. SidebarSeparator supports decorative or semantic separators and orientation, but no longer inherits a generic Separator color variant that its sidebar-border treatment always overrode. Keep the contextual sidebar separator rather than recoloring it from a caller.

Use SidebarMenuButton for an action, SidebarMenuLink for a main navigation destination and SidebarMenuSubLink for a nested destination. Links own a native href, retain link semantics and support ordinary Enter, modifier-click and context-menu navigation. SidebarMenuSubButton was removed: its default element was an anchor, not an action button.

tsx
<SidebarMenuItem>  <SidebarMenuLink href="/projects">Projects</SidebarMenuLink></SidebarMenuItem><SidebarMenuSubItem>  <SidebarMenuSubLink    aria-describedby="unavailable-feature-reason"    disabled    href="/knowledge"  >    Knowledge base  </SidebarMenuSubLink>  <span className="sr-only" id="unavailable-feature-reason">    Available after your administrator enables this feature.  </span></SidebarMenuSubItem>

Native actions use type="button" by default, including when a tooltip is present. Disabled actions cannot activate or submit an enclosing form. Disabled links retain aria-disabled link semantics, remove their navigable href, reject activation and leave the sequential Tab order. Keep the reason persistently associated with aria-describedby; a visual tooltip alone is not an accessible explanation. Use useId when repeated instances need unique description IDs.

Enabled controls still accept Base UI render composition, including a router link that forwards its native props and ref. Do not combine disabled with render. The type contract rejects it and JavaScript consumers receive a descriptive error. A custom renderer can replace navigation attributes or execute its own handlers before merged owner handlers; Sidebar cannot honestly guarantee its disabled behavior. When availability is conditional, render the disabled native action/link branch without render, and use the router-rendered branch only when enabled.

When to use

Sidebars provide persistent navigation and complementary content. Use this decision tree:

Usage

tsx
<SidebarProvider>  <Sidebar>    <SidebarHeader>      <SidebarMenu>        <SidebarMenuItem>Item 1</SidebarMenuItem>        <SidebarMenuItem>Item 2</SidebarMenuItem>        <SidebarMenuItem>Item 3</SidebarMenuItem>      </SidebarMenu>    </SidebarHeader>    <SidebarContent>      <SidebarGroup>        <SidebarGroupLabel>Label 1</SidebarGroupLabel>        <SidebarMenu>          <SidebarMenuItem>Item 1</SidebarMenuItem>          <SidebarMenuItem>Item 2</SidebarMenuItem>          <SidebarMenuItem>Item 3</SidebarMenuItem>        </SidebarMenu>      </SidebarGroup>      <SidebarGroup>        <SidebarGroupLabel>Label 2</SidebarGroupLabel>        <SidebarMenu>          <SidebarMenuItem>Item 1</SidebarMenuItem>          <SidebarMenuItem>Item 2</SidebarMenuItem>          <SidebarMenuItem>Item 3</SidebarMenuItem>        </SidebarMenu>      </SidebarGroup>    </SidebarContent>    <SidebarFooter>      <SidebarMenu>        <SidebarMenuItem>Item 1</SidebarMenuItem>        <SidebarMenuItem>Item 2</SidebarMenuItem>        <SidebarMenuItem>Item 3</SidebarMenuItem>      </SidebarMenu>    </SidebarFooter>    <SidebarRail />  </Sidebar>  <SidebarInset>    <SidebarTrigger />    {...}  </SidebarInset></SidebarProvider>

Props

Animate UI props

PropType
containerClassName?string

The class name of the sidebar container

Typestring
animateOnHover?boolean

Whether to animate the sidebar on hover

Typeboolean
Defaulttrue
transition?Transition

The transition of the sidebar

TypeTransition
Default{ type: "spring", stiffness: 350, damping: 35 }

Examples

Loading skeleton

SidebarMenuSkeleton renders random per-row widths by default. Pass uniform for full-width rows that match evenly sized nav items.

Wide content in the inset

SidebarInset sets min-w-0 so it can shrink below its content’s intrinsic width. Without it, a flex item’s implicit min-width: auto lets one wide descendant — a long code line, a wide table — widen the whole shell and scroll the document horizontally. The wide block still needs its own overflow-x-auto, as the pre here has: that is what gives the overflow somewhere to go instead of spilling out of the inset.

With a fixed banner

Pass bannerHeight on SidebarProvider so the sidebar container and inset are offset below a fixed top banner. The mobile dialog is intentionally not offset: it slides over the banner. This app-shell example uses a collapsible Sidebar and SidebarInset; collapsible="none" stays inline and does not consume the fixed-container offset. The example also uses SidebarMenuBadge variant="secondary" for emphasis badges next to nav items.

The application examples share their actual navigation catalogs and Cloud shell rather than copying menu markup. Navigation leaves are native links; only groups with children are disclosure buttons. The Cluster and Serverless examples expose the authored AI Agents children, including the unavailable Knowledge Base and its reason. Their # destinations are illustrative document-top links, not simulated backend routes. The Admin and Console integration branding is noninteractive; the billing examples retain their distinct expired-trial and remaining-balance features.

Cloud UI

An example sidebar representation for Cloud UI.

Cloud UI (With Billing credits)

The billing examples use a small standard Card and a primary Upgrade action. The balance example keeps the remaining days and available credits visible. Collapsed sidebars provide a named review button that opens the same details and Upgrade action; mobile sidebars present those details in a drawer.

An example sidebar representation for Cloud UI with billing credits for a free trial.

Cloud UI (With Billing expired)

An example sidebar representation for Cloud UI with billing free trial expired.

Cloud UI (Cluster)

An example sidebar representation for Cloud UI within a cluster.

Cloud UI (Serverless)

An example sidebar representation for Cloud UI within a serverless cluster.

Console UI

An example sidebar representation for Console UI.

Console UI (Self-hosted)

An example sidebar representation for self-hosted Console UI.

Admin UI

An example sidebar representation for Admin UI.

Credits

Recent changes

  • patchv1.2.0Pin shipped dependency floors to the version we develop against. Registry items now declare ranges like `^5.1.9` (the actual installed version) instead of collapsing to `^5.0.0`, so consumers start on the known-tested baseline while caret semantics still allow any compatible release within the same major.#133
  • minorv1.1.0Theme docs refresh, readability pass on semantic foregrounds, and consumer-facing Base UI regression fixes.#121
  • minorv1.0.0Post-Base-UI polish. Public API unchanged.#116
  • majorv1.0.0Migrate every Radix-based primitive to `@base-ui/react@^1.4.0` (Base UI).#114
  • patchv0.3.1## 🚧 Updated#112
See full history →

Last updated on

Was this page helpful?