{"record":{"id":"738dcb7ad5b5b192","repo":"shadcn-ui/ui","slug":"usetheme-must-be-used-within-a-themeprovider-738dcb","errorCode":null,"errorMessage":"useTheme must be used within a ThemeProvider","messagePattern":"useTheme must be used within a ThemeProvider","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"templates/vite-monorepo/apps/web/src/components/theme-provider.tsx","lineNumber":226,"sourceCode":"    () => ({\n      theme,\n      setTheme,\n    }),\n    [theme, setTheme]\n  )\n\n  return (\n    <ThemeProviderContext.Provider {...props} value={value}>\n      {children}\n    </ThemeProviderContext.Provider>\n  )\n}\n\nexport const useTheme = () => {\n  const context = React.useContext(ThemeProviderContext)\n\n  if (context === undefined) {\n    throw new Error(\"useTheme must be used within a ThemeProvider\")\n  }\n\n  return context\n}\n","sourceCodeStart":208,"sourceCodeEnd":231,"githubUrl":"https://github.com/shadcn-ui/ui/blob/efac5987074af84ece57c367c6dd83387b967022/templates/vite-monorepo/apps/web/src/components/theme-provider.tsx#L208-L231","documentation":"This error is thrown by the useTheme hook when React.useContext(ThemeProviderContext) returns undefined. The context is created with a default value of undefined (line 22-24), so any component consuming useTheme that is NOT rendered as a descendant of <ThemeProvider> reads undefined and the guard at line 225 throws. It is the standard 'hook used outside its provider' fail-fast pattern that prevents silently operating on missing theme state.","triggerScenarios":"Calling useTheme() in a component that is rendered outside the <ThemeProvider> subtree. Concrete cases in this template: (1) a component placed in main.tsx or App.tsx ABOVE or as a sibling to <ThemeProvider>, (2) a component rendered through a portal whose React tree parent is not ThemeProvider, (3) using useTheme in a Storybook story or unit test (Vitest/RTL) without wrapping the component in ThemeProvider, (4) a second root created with ReactDOM.createRoot that is not wrapped, (5) an error boundary's fallback component that calls useTheme but is mounted outside the provider.","commonSituations":"Adding a new component that needs the current theme but forgetting to place it inside the provider tree; restructuring the app entry (main.tsx) and accidentally moving ThemeProvider below the component; testing components in isolation without the provider decorator; SSR or pre-render paths where a theme-consuming component renders before ThemeProvider mounts; refactoring that splits the tree into multiple roots; upgrading a shadcn-style theme setup and losing the provider wrapper.","solutions":["Ensure the component calling useTheme is a descendant of <ThemeProvider> in the React tree. Move it inside the provider in your entry file, e.g. wrap <App/> with <ThemeProvider defaultTheme=\"system\" storageKey=\"theme\"> so every consumer sits beneath it.","If the error surfaces in tests, wrap the rendered component: render(<ThemeProvider><MyComponent/></ThemeProvider>) in Vitest/RTL, or add a global decorator in Storybook (parameters.decorators) that supplies ThemeProvider.","If a portal or separate React root needs the theme, either render it within the existing provider tree, or mount an additional <ThemeProvider> around that secondary root.","Provide a safe fallback by guarding before calling useTheme: check React.useContext(ThemeProviderContext) directly and supply a default instead of throwing, if a missing provider is an expected state.","Remove the useTheme call from components that do not strictly need live theme state, or pass theme/setTheme down as explicit props from a component that is already inside the provider."],"exampleFix":"// before (main.tsx) — App renders above/without ThemeProvider\nReactDOM.createRoot(document.getElementById('root')!).render(\n  <React.StrictMode>\n    <App />\n  </React.StrictMode>\n)\n\n// after — ThemeProvider wraps the entire consuming tree\nReactDOM.createRoot(document.getElementById('root')!).render(\n  <React.StrictMode>\n    <ThemeProvider defaultTheme=\"system\" storageKey=\"theme\">\n      <App />\n    </ThemeProvider>\n  </React.StrictMode>\n)","handlingStrategy":"validation","validationCode":"import * as React from 'react'\nimport { ThemeProviderContext } from './theme-provider'\n\nfunction useThemeOptional(defaultValue = { theme: 'system' as const, setTheme: () => {} }) {\n  const ctx = React.useContext(ThemeProviderContext)\n  if (ctx === undefined) {\n    // Caller is outside ThemeProvider; avoid throwing by returning a default.\n    return defaultValue\n  }\n  return ctx\n}","typeGuard":"import * as React from 'react'\nimport { ThemeProviderContext, type ThemeProviderState } from './theme-provider'\n\nfunction hasThemeProvider(ctx: unknown): ctx is ThemeProviderState {\n  return (\n    typeof ctx === 'object' &&\n    ctx !== null &&\n    'theme' in ctx &&\n    typeof (ctx as ThemeProviderState).setTheme === 'function'\n  )\n}\n\n// usage:\n//   const ctx = React.useContext(ThemeProviderContext)\n//   if (!hasThemeProvider(ctx)) return null // or render a fallback","tryCatchPattern":"// React render throws are not catchable by try/catch around useTheme.\n// Guard at the component boundary instead:\nfunction MyComponent() {\n  const ctx = React.useContext(ThemeProviderContext)\n  if (ctx === undefined) {\n    // Render a non-theme-dependent fallback rather than calling useTheme\n    return <div>Theme unavailable</div>\n  }\n  // ctx is now narrowed to ThemeProviderState\n  return <div>Current theme: {ctx.theme}</div>\n}","preventionTips":["Establish a single root-level <ThemeProvider> in the app entry (main.tsx) that wraps the entire component tree so every consumer is guaranteed a provider.","Add a test helper/decorator (Vitest RTL wrapper, Storybook decorator) that mounts ThemeProvider around any component under test that calls useTheme.","Audit new components during code review: any useTheme import must trace back to a node inside the provider subtree.","For portals and secondary roots, either re-mount ThemeProvider or consume the context from the original tree via a ref/props instead of a fresh useTheme call.","If you need graceful degradation, consume ThemeProviderContext directly and supply a fallback rather than using the throwing useTheme hook."],"tags":["react","context","theming","hook","provider","shadcn-ui"],"backgroundTag":null,"analyzedSha":"efac5987074af84ece57c367c6dd83387b967022","analyzedAt":"2026-08-12T05:00:50.218Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}