Diagnosing Chakra UI Theme Customization Failures: A Step-by-Step Guide
A diagnostic guide for Chakra UI v2/v3 theme customization failures: custom colors, component overrides, color mode, responsive props, TypeScript errors, FOUC, portal context, and migration issues. Includes cause table, ordered checks, fixes, and escalation criteria.
05 Jul 2025, 09:03 UTC

Recognizable Condition
You’ve added custom colors, component overrides, or color‑mode logic to your Chakra UI theme, but the rendered components still show fallback values, ignore your overrides, or fail to switch between light and dark mode. The theme object looks correct in code, yet the UI doesn’t reflect it.
Quick Cause‑Diagnostic Table
| Symptom | Most Likely Cause |
|---|---|
Custom theme colors (e.g., brand.500) return fallback or undefined | ChakraProvider not wrapping the component tree, or theme object not merged via extendTheme before passing to provider |
Component style overrides (e.g., Button.baseStyle) ignored | Override keys mismatched (using Button vs Button in components section) or using v1 component names in v2/v3 (e.g., CButton vs Button) |
Dark mode colors not switching despite useColorModeValue or _dark pseudo‑prop | ColorModeScript missing from document head (SSR), or CSS variable generation disabled in theme config (cssVarRoot !== ':root') |
Responsive style props (e.g., fontSize={{ base: 'md', md: 'lg' }}) not applying at breakpoints | Breakpoint values in theme not matching default or custom breakpoints array, or missing theme.breakpoints in extendTheme |
TypeScript errors on custom theme tokens (e.g., theme.colors.brand) | Module augmentation missing for @chakra-ui/react or @chakra-ui/theme to extend Theme interface with custom keys |
| Styles flicker on initial load (FOUC) in Next.js/Pages Router | ColorModeScript not placed in _document.js/_app.tsx before hydration, or getInitialColorModeConfig not returning correct initial mode |
| Portal‑based components (Modal, Popover) render outside theme context | PortalManager missing from root, or portalZIndex theme values conflicting with app stacking context |
| Migration from v1 to v2/v3 breaks theme: color mode, spacing, or component props changed | v1 used colorMode prop on ChakraProvider; v2/v3 uses colorModeManager and CSS variables. Component prop names changed (e.g., size → variant in some) |
Ordered Diagnostic Checks
- Verify Provider Wrapping – Open React DevTools, locate
ChakraProviderin the component tree, and confirm itsthemeprop shows your merged custom tokens (e.g.,colors.brand.500). - Inspect CSS Variables – In browser DevTools Elements tab, check the
:rootorhtmlelement for--chakra-colors-brand-500. Absence means CSS variable generation failed orcssVarRootis misconfigured. - Log Runtime Theme – Temporarily add
console.log(useTheme())inside a component to see the actual theme shape at runtime. - Run TypeScript Check – Execute
tsc --noEmitin your project root (requires Node ≥14, write access totsconfig.json). Errors on custom tokens indicate missing module augmentation. - Test Color Mode Toggle – Toggle color mode via UI; verify
data-themeattribute onhtml/bodyupdates and CSS variables change accordingly. - Check Breakpoint Definitions – Ensure
theme.breakpointsinextendThemematches the responsive prop keys (e.g.,base,md) and values are strings with units sorted ascending (['480px', '768px', '992px']). - Validate Portal Manager – Confirm
PortalManageris rendered at the root of your app (typically insideChakraProvider).
Fixes Tied to Findings
1. Provider Not Wrapping / Theme Not Merged
// theme.ts
import { extendTheme } from '@chakra-ui/react'
export const theme = extendTheme({
colors: {
brand: {
500: '#3182ce',
600: '#2c5282',
},
},
// Ensure breakpoints are defined if you use responsive props
breakpoints: {
base: '0px',
sm: '480px',
md: '768px',
lg: '992px',
xl: '1280px',
},
})
// _app.tsx (Next.js Pages) or main.tsx (Vite/CRA)
import { ChakraProvider } from '@chakra-ui/react'
import { theme } from './theme'
export default function App({ Component, pageProps }) {
return (
<ChakraProvider theme={theme}>
<Component {...pageProps} />
</ChakraProvider>
)
}
Risk: Forgetting to spread existing theme keys when overriding nested objects (e.g., components.Button.variants) replaces the entire object. Manually spread if you need to keep defaults.
2. Component Override Keys Mismatched
In v2/v3, component keys are singular PascalCase (Button, Input). Ensure your extendTheme components section matches exactly:
const theme = extendTheme({
components: {
Button: {
baseStyle: { fontWeight: 'bold' },
variants: {
solid: (props) => ({
bg: props.colorMode === 'dark' ? 'brand.500' : 'brand.600',
}),
},
},
},
})
Do not use CButton (v1) or button (lowercase).
3. Dark Mode Not Switching
- Add
ColorModeScriptin_document.js(Pages Router) or a client‑side wrapper (App Router) before hydration:// pages/_document.js import { ColorModeScript } from '@chakra-ui/react' export default function Document() { return ( <Html> <Head> <ColorModeScript initialColorMode="system" /> </Head> <body><Main /><NextScript /></body> </Html> ) } - Ensure
cssVarRootis set to':root'(default) in theme config; setting it tonulldisables CSS variables and forces inline styles (IE11 fallback).
4. Responsive Props Not Applying
Define breakpoints in theme and use the same keys in responsive objects:
const theme = extendTheme({
breakpoints: {
sm: '480px',
md: '768px',
lg: '992px',
},
})
// Usage
<Box fontSize={{ base: 'md', md: 'lg', lg: 'xl' }} />
Mismatched keys (e.g., using sm in prop but not in theme) cause silent failures.
5. TypeScript Errors on Custom Tokens
Create a declaration file (e.g., types/chakra.d.ts) included in tsconfig.json include array:
// types/chakra.d.ts
import '@chakra-ui/react'
declare module '@chakra-ui/react' {
export interface Theme {
colors: {
brand: {
500: string
600: string
}
}
}
}
Run tsc --noEmit to verify.
6. FOUC in Next.js
Place ColorModeScript in _document.js (Pages) or a client component wrapper (App Router). Use getInitialColorModeConfig to return the correct initial mode from cookies/localStorage.
7. Portal Components Outside Theme
Add PortalManager at the root inside ChakraProvider:
<ChakraProvider theme={theme}>
<PortalManager />
<App />
</ChakraProvider>
Adjust portalZIndex in theme if stacking conflicts occur.
8. Migration from v1 to v2/v3
- Replace
colorModeprop onChakraProviderwithcolorModeManager(or rely on default). - Update component prop names (e.g.,
size→variantfor some components). - Switch to CSS variable based theming; ensure
cssVarRootis notnullunless targeting IE11.
Escalation Criteria
- After completing all checks, the symptom persists – create a minimal reproduction in CodeSandbox/StackBlitz with the exact Chakra version to isolate config vs. app issues.
- TypeScript errors remain after correct module augmentation – verify
tsconfig.jsonincludes the.d.tsfile andskipLibCheckis not hiding errors. - CSS variables appear in DevTools but components still use fallbacks – inspect component’s computed styles for inline style overrides (possible
cssVarRootmismatch). - Portal components still unthemed – confirm no other
ChakraProviderhigher in the tree withoutPortalManager.
Limitations & Version Assumptions
- This guide assumes Chakra UI v2 (stable) or v3 (beta/RC as of 2024). v3 introduces a CSS‑in‑JS engine swap (Emotion → Panda CSS), new theme structure, and different component APIs. Always verify your installed version (
npm list @chakra-ui/react) before applying fixes. extendThemedeep‑merges only top‑level keys; nested objects likecomponents.Button.variantsare replaced entirely unless manually spread.- CSS variable mode requires modern browsers; IE11 needs polyfill or fallback via
cssVarRoot: null. - Module augmentation must be in a
.d.tsfile included intsconfig.json, not in.tsxcomponents. - Next.js App Router requires
'use client'on components usinguseColorMode;ColorModeScriptmust be in a Client Component wrapper. - Custom breakpoints must be strings with units (e.g.,
'480px') and sorted ascending; mismatched units cause silent failures.
Practical Verification Checklist
- Run
npm list @chakra-ui/reactto confirm version. - Open React DevTools → select
ChakraProvider→ inspectthemeprop for custom tokens. - In browser DevTools Elements, search for
--chakra-colors-brand-500on:root. - Execute
tsc --noEmitin project root (requires Node, write access totsconfig.json). - Toggle color mode via UI; watch
data-themeattribute and CSS variable updates. - If using Next.js, verify
ColorModeScriptloads before hydration (view page source). - Create a minimal reproduction if issues persist; share exact version and config for community support.
Following this diagnostic flow should resolve the majority of theme customization failures. When in doubt, isolate the problem in a minimal sandbox – it’s the fastest way to distinguish configuration errors from framework bugs.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.