{"record":{"id":"60542e728b95162b","repo":"shadcn-ui/ui","slug":"uselayout-must-be-used-within-a-layoutprovider","errorCode":null,"errorMessage":"useLayout must be used within a LayoutProvider","messagePattern":"useLayout must be used within a LayoutProvider","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"apps/v4/hooks/use-layout.tsx","lineNumber":38,"sourceCode":"}\n\nconst isServer = typeof window === \"undefined\"\nconst LayoutContext = React.createContext<LayoutProviderState | undefined>(\n  undefined\n)\n\nconst saveToLS = (storageKey: string, value: string) => {\n  try {\n    localStorage.setItem(storageKey, value)\n  } catch {\n    // Unsupported\n  }\n}\n\nconst useLayout = () => {\n  const context = React.useContext(LayoutContext)\n  if (context === undefined) {\n    throw new Error(\"useLayout must be used within a LayoutProvider\")\n  }\n  return context\n}\n\nconst Layout = ({\n  forcedLayout,\n  storageKey = \"layout\",\n  defaultLayout = \"full\",\n  attribute = \"class\",\n  value,\n  children,\n}: LayoutProviderProps) => {\n  const [layout, setLayoutState] = React.useState<Layout>(() => {\n    if (isServer) return defaultLayout\n    try {\n      const saved = localStorage.getItem(storageKey)\n      if (saved === \"fixed\" || saved === \"full\") {\n        return saved","sourceCodeStart":20,"sourceCodeEnd":56,"githubUrl":"https://github.com/shadcn-ui/ui/blob/efac5987074af84ece57c367c6dd83387b967022/apps/v4/hooks/use-layout.tsx#L20-L56","documentation":"`useLayout` reads `LayoutContext`; `Layout` (the provider component) computes layout state from `forcedLayout`, `storageKey`, `defaultLayout`, `attribute`, and persisted localStorage. When `useContext(LayoutContext) === undefined` the hook throws — consumers (e.g. layout switchers) must receive a concrete layout value.","triggerScenarios":"Calling `useLayout()` in a component not under `<Layout>`. Notable: the provider persists to localStorage and silently swallows storage errors (`// Unsupported`), but that does NOT cause this throw — the throw is purely the missing-provider case.","commonSituations":"Mounting a layout-aware component in a route segment above the `<Layout>` wrapper; SSR where the provider is conditionally skipped; tests rendering a layout consumer in isolation.","solutions":["Wrap the tree (usually at the app root) in `<Layout storageKey=\"layout\" defaultLayout=\"full\">`.","Move any layout-aware component below the `<Layout>` wrapper.","Decorate tests with `<Layout>` (and stub localStorage if needed)."],"exampleFix":"// before\n<LayoutSwitcher />\n\n// after\n<Layout storageKey=\"layout\" defaultLayout=\"full\">\n  <LayoutSwitcher />\n</Layout>","handlingStrategy":"type-guard","validationCode":"render(<Layout storageKey=\"layout\" defaultLayout=\"full\">{<LayoutSwitcher/>}</Layout>)","typeGuard":"import React from \"react\"\nimport { LayoutContext } from \"@/hooks/use-layout\"\nconst hasLayout = () => React.useContext(LayoutContext) !== undefined","tryCatchPattern":"try { useLayout() } catch (e) { if (e.message.includes(\"LayoutProvider\")) {/*mount <Layout>*/} throw e }","preventionTips":["Mount <Layout> at the app root, above all layout-aware components.","Note: localStorage failures are swallowed by the provider (\"Unsupported\"), so they are NOT the cause of this throw — focus on provider placement.","Add <Layout> to story/test decorators."],"tags":["react","context","hooks","shadcn-v4","layout","localstorage"],"backgroundTag":null,"analyzedSha":"efac5987074af84ece57c367c6dd83387b967022","analyzedAt":"2026-08-12T05:00:50.218Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}