shadcn-ui/ui · error · Error

useSidebar must be used within a SidebarProvider.

Error message

useSidebar must be used within a SidebarProvider.

What it means

`useSidebar` reads `SidebarContext` (`createContext<SidebarContextProps | null>(null)`); `<SidebarProvider>` supplies open/openMobile state, setOpen/setOpenMobile, isMobile, toggleSidebar. Any sidebar part (Sidebar/SidebarTrigger/Menu/Inset/etc.) rendered outside `<SidebarProvider>` throws so the open/keyboard state contract holds.

Source

Thrown at apps/v4/registry/bases/aria/ui/sidebar.tsx:53

  state: "expanded" | "collapsed"
  open: boolean
  setOpen: (open: boolean) => void
  openMobile: boolean
  setOpenMobile: (open: boolean) => void
  isMobile: boolean
  toggleSidebar: () => void
}

type SidebarButtonProps =
  | (LinkProps & { href: string })
  | (ButtonProps & { href?: never })

const SidebarContext = React.createContext<SidebarContextProps | null>(null)

function useSidebar() {
  const context = React.useContext(SidebarContext)
  if (!context) {
    throw new Error("useSidebar must be used within a SidebarProvider.")
  }

  return context
}

function SidebarProvider({
  defaultOpen = true,
  open: openProp,
  onOpenChange: setOpenProp,
  className,
  style,
  children,
  ...props
}: React.ComponentProps<"div"> & {
  defaultOpen?: boolean
  open?: boolean
  onOpenChange?: (open: boolean) => void
}) {

View on GitHub (pinned to efac598707)

Solutions

  1. Wrap the whole app shell (header + sidebar + main) in `<SidebarProvider>` so every sidebar part — including `<SidebarTrigger />` in the header — is a descendant.
  2. If SidebarProvider reads from cookies/localStorage, keep it at the root layout to avoid remounts resetting state.
  3. Decorate tests/stories with `<SidebarProvider>`.

Example fix

// before
<header>
  <SidebarTrigger />
</header>
<SidebarProvider>
  <Sidebar />
</SidebarProvider>

// after
<SidebarProvider>
  <header>
    <SidebarTrigger />
  </header>
  <Sidebar />
</SidebarProvider>
Defensive patterns

Strategy: type-guard

Validate before calling

render(<SidebarProvider><header><SidebarTrigger/></header><Sidebar/></SidebarProvider>)

Type guard

import React from "react"
import { SidebarContext } from "@/registry/bases/aria/ui/sidebar"
const insideSidebar = () => React.useContext(SidebarContext) != null

Try / catch

try { useSidebar() } catch (e) { if (e.message.includes("SidebarProvider.")) {/*wrap shell in SidebarProvider*/} throw e }

Prevention

When it happens

Trigger: Mounting `<SidebarTrigger />`, `<Sidebar />`, `<SidebarInset />`, or menu items outside `<SidebarProvider>`. Common when the trigger is placed in a top-level header that sits above the provider, or when sidebar markup is split across route segments without a shared provider.

Common situations: Reorganizing the app shell so the header (with SidebarTrigger) is no longer under SidebarProvider; SSR rendering order; tests of individual sidebar parts.

Related errors


AI-assisted analysis of shadcn-ui/ui@efac598707 (2026-08-12). Data as JSON: /api/errors/22eb8e097dec2b67. Report an issue: GitHub.