Fix: Chakra UI Not Working — Provider Missing, Styles Not Applied, or Dark Mode Broken
Part of: React & Frontend Errors
Quick Answer
How to fix Chakra UI v3 issues — ChakraProvider setup, color mode, theming, server-side rendering in Next.js, component styling, and common runtime errors.
The Problem
Chakra UI components render unstyled or with broken layout:
// Components appear but have no Chakra styles
<Button colorScheme="blue">Click me</Button>
// Renders as plain HTML button with no color or paddingOr the app crashes with a missing context error:
Error: useChakra must be used within a ChakraProvider.Or dark mode doesn’t apply correctly:
const { colorMode, toggleColorMode } = useColorMode();
// Toggling fires but the UI doesn't change to dark themeWhy This Happens
Chakra UI v3 (released late 2024) changed significantly from v2. The provider, theming, and color mode APIs are all different — mixing v2 and v3 patterns is the most common source of errors. Search results for “Chakra UI provider” still skew toward v2 patterns, which is why so many setup attempts produce unstyled components. The package name stayed the same (@chakra-ui/react), so a copy-pasted v2 snippet installs cleanly but throws at runtime.
ChakraProvideris required — every Chakra component reads from context. Without the provider wrapping your app, components have no styles or theme. In v3, that context object is called a “system” and is created withcreateSystem(). In v2, it was a plain theme object created withextendTheme(). The two are not interchangeable.- Color mode in v3 uses CSS variables — v3 handles dark mode differently than v2. The
ColorModeProvideris built intoChakraProvider, and the toggle works via a CSS class on<html>. v3 also delegates persistence tonext-themes, which means you must install and wire that package separately if you want the theme to survive a reload. - SSR requires special handling — in Next.js App Router, the provider must be in a Client Component. Running Chakra during server rendering without the correct setup causes hydration mismatches. The mismatch is silent in development and only appears in production builds, which is why “works locally, broken on Vercel” is a common report.
- v2 vs v3 API — if you’re following v2 docs, components like
useColorMode,extendTheme, andChakraProviderhave different import paths and behavior in v3. Some props (spacing,isLoading) still work as aliases but emit deprecation warnings, while others (extendTheme) throw outright.
A third class of failure relates to peer dependencies. v2 required @emotion/react, @emotion/styled, and framer-motion. v3 dropped @emotion/styled and framer-motion from the required set but kept @emotion/react. If npm ls shows a stale framer-motion from a v2 install, components that animate (Modal, Drawer) will silently downgrade to no-transition fallbacks.
Fix 1: Installation and Provider Setup (v3)
# Chakra UI v3
npm install @chakra-ui/react @emotion/react// app/providers.tsx — wrap with ChakraProvider in a Client Component
'use client';
import { ChakraProvider, defaultSystem } from '@chakra-ui/react';
export function Providers({ children }: { children: React.ReactNode }) {
return (
<ChakraProvider value={defaultSystem}>
{children}
</ChakraProvider>
);
}
// app/layout.tsx — use the providers component
import { Providers } from './providers';
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>
<Providers>{children}</Providers>
</body>
</html>
);
}Note: In Chakra UI v3, ChakraProvider accepts a value prop that takes a system configuration object (from createSystem or the built-in defaultSystem). This replaces v2’s theme prop.
Fix 2: Chakra UI v2 Setup (Legacy)
If you’re on Chakra UI v2 (still widely used), the setup is different:
# Chakra UI v2
npm install @chakra-ui/react @emotion/react @emotion/styled framer-motion// pages/_app.tsx (Pages Router)
import { ChakraProvider } from '@chakra-ui/react';
import type { AppProps } from 'next/app';
export default function App({ Component, pageProps }: AppProps) {
return (
<ChakraProvider>
<Component {...pageProps} />
</ChakraProvider>
);
}// app/providers.tsx (App Router with v2)
'use client';
import { CacheProvider } from '@chakra-ui/next-js';
import { ChakraProvider } from '@chakra-ui/react';
export function Providers({ children }: { children: React.ReactNode }) {
return (
<CacheProvider>
<ChakraProvider>
{children}
</ChakraProvider>
</CacheProvider>
);
}# v2 App Router also requires:
npm install @chakra-ui/next-jsFix 3: Theming and Custom Tokens (v3)
// lib/theme.ts — custom system with Chakra UI v3
import { createSystem, defaultConfig, defineConfig } from '@chakra-ui/react';
const config = defineConfig({
theme: {
tokens: {
colors: {
brand: {
50: { value: '#e3f9e5' },
100: { value: '#c1eac5' },
200: { value: '#a3d9a5' },
300: { value: '#7bc47f' },
400: { value: '#57ae5b' },
500: { value: '#3f9142' },
600: { value: '#2f8132' },
700: { value: '#207227' },
800: { value: '#0e5814' },
900: { value: '#05400a' },
},
},
fonts: {
heading: { value: 'Inter, sans-serif' },
body: { value: 'Inter, sans-serif' },
},
},
semanticTokens: {
colors: {
'chakra-body-bg': {
_light: { value: 'white' },
_dark: { value: 'gray.900' },
},
},
},
},
});
export const system = createSystem(defaultConfig, config);
// app/providers.tsx
import { ChakraProvider } from '@chakra-ui/react';
import { system } from '@/lib/theme';
export function Providers({ children }: { children: React.ReactNode }) {
return <ChakraProvider value={system}>{children}</ChakraProvider>;
}// v2 custom theme — extendTheme (v2 only)
import { extendTheme } from '@chakra-ui/react';
const theme = extendTheme({
colors: {
brand: {
500: '#3f9142',
},
},
fonts: {
heading: 'Inter, sans-serif',
body: 'Inter, sans-serif',
},
config: {
initialColorMode: 'light',
useSystemColorMode: false,
},
});
// <ChakraProvider theme={theme}>Fix 4: Dark Mode (Color Mode)
// v3 dark mode — uses ColorModeButton from snippets
// Install via CLI: npx @chakra-ui/cli snippet add color-mode
// Or manually:
// components/color-mode.tsx (generated snippet)
'use client';
import { ClientOnly, IconButton, Skeleton, useColorMode } from '@chakra-ui/react';
import { ThemeProvider, useTheme } from 'next-themes';
import type { IconButtonProps } from '@chakra-ui/react';
export function ColorModeProvider({ children }: { children: React.ReactNode }) {
return (
<ThemeProvider attribute="class" disableTransitionOnChange>
{children}
</ThemeProvider>
);
}
// Wrap providers:
// <ChakraProvider value={system}>
// <ColorModeProvider>
// {children}
// </ColorModeProvider>
// </ChakraProvider>// v2 dark mode — simpler
'use client';
import { useColorMode, Button } from '@chakra-ui/react';
export function ColorModeToggle() {
const { colorMode, toggleColorMode } = useColorMode();
return (
<Button onClick={toggleColorMode}>
{colorMode === 'light' ? 'Dark' : 'Light'} Mode
</Button>
);
}// v2 — fix "flash of incorrect theme" (FOUC) in Next.js
// pages/_document.tsx
import { ColorModeScript } from '@chakra-ui/react';
import { Html, Head, Main, NextScript } from 'next/document';
import theme from '../lib/theme';
export default function Document() {
return (
<Html lang="en">
<Head />
<body>
{/* Must be before <Main /> to prevent FOUC */}
<ColorModeScript initialColorMode={theme.config.initialColorMode} />
<Main />
<NextScript />
</body>
</Html>
);
}Fix 5: Common Components
// Box, Stack, Flex — layout primitives
import { Box, Stack, HStack, VStack, Flex, Grid, GridItem } from '@chakra-ui/react';
<Box p={4} bg="blue.50" borderRadius="md">
Content
</Box>
<HStack spacing={4} align="center">
<Box>Item 1</Box>
<Box>Item 2</Box>
</HStack>
<Grid templateColumns="repeat(3, 1fr)" gap={6}>
<GridItem><Box bg="gray.100" p={4}>Col 1</Box></GridItem>
<GridItem><Box bg="gray.100" p={4}>Col 2</Box></GridItem>
<GridItem><Box bg="gray.100" p={4}>Col 3</Box></GridItem>
</Grid>// Responsive styles — array or object syntax
<Box
fontSize={{ base: 'sm', md: 'md', lg: 'lg' }} // Object syntax
p={[2, 4, 6]} // Array: base, sm, md
display={{ base: 'none', md: 'block' }}
>
Responsive content
</Box>// Form with validation
import {
FormControl, FormLabel, FormErrorMessage, FormHelperText,
Input, Button, useToast
} from '@chakra-ui/react';
import { useForm } from 'react-hook-form';
export function LoginForm() {
const toast = useToast();
const { register, handleSubmit, formState: { errors, isSubmitting } } = useForm();
const onSubmit = async (data) => {
try {
await login(data);
toast({ title: 'Logged in!', status: 'success', duration: 3000 });
} catch (err) {
toast({ title: 'Error', description: err.message, status: 'error' });
}
};
return (
<form onSubmit={handleSubmit(onSubmit)}>
<FormControl isInvalid={!!errors.email} mb={4}>
<FormLabel>Email</FormLabel>
<Input
type="email"
{...register('email', {
required: 'Email is required',
pattern: { value: /\S+@\S+\.\S+/, message: 'Invalid email' },
})}
/>
<FormErrorMessage>{errors.email?.message as string}</FormErrorMessage>
</FormControl>
<FormControl isInvalid={!!errors.password} mb={4}>
<FormLabel>Password</FormLabel>
<Input
type="password"
{...register('password', { required: 'Password is required', minLength: 8 })}
/>
<FormErrorMessage>{errors.password?.message as string}</FormErrorMessage>
</FormControl>
<Button type="submit" colorScheme="blue" isLoading={isSubmitting} width="full">
Log In
</Button>
</form>
);
}// Modal
import { useDisclosure, Modal, ModalOverlay, ModalContent, ModalHeader,
ModalBody, ModalFooter, ModalCloseButton, Button } from '@chakra-ui/react';
export function ConfirmModal({ onConfirm }: { onConfirm: () => void }) {
const { isOpen, onOpen, onClose } = useDisclosure();
return (
<>
<Button colorScheme="red" onClick={onOpen}>Delete</Button>
<Modal isOpen={isOpen} onClose={onClose}>
<ModalOverlay />
<ModalContent>
<ModalHeader>Confirm Delete</ModalHeader>
<ModalCloseButton />
<ModalBody>Are you sure? This action cannot be undone.</ModalBody>
<ModalFooter>
<Button variant="ghost" mr={3} onClick={onClose}>Cancel</Button>
<Button colorScheme="red" onClick={() => { onConfirm(); onClose(); }}>Delete</Button>
</ModalFooter>
</ModalContent>
</Modal>
</>
);
}Fix 6: SSR Hydration Issues
// Hydration mismatch — use ClientOnly for components that read color mode
import { ClientOnly, Skeleton } from '@chakra-ui/react';
function ColorAwareComponent() {
return (
<ClientOnly fallback={<Skeleton height="40px" />}>
<ComponentThatUsesColorMode />
</ClientOnly>
);
}// v2 — avoid hydration mismatch with useColorModeValue
import { useColorModeValue } from '@chakra-ui/react';
function Card() {
const bg = useColorModeValue('white', 'gray.800');
const color = useColorModeValue('gray.800', 'white');
return (
<Box bg={bg} color={color} p={4} borderRadius="md">
Content
</Box>
);
}Common Mistake: Accessing localStorage in SSR causes hydration mismatches. Chakra v2’s ColorModeScript in _document.tsx prevents this for color mode, but any component that reads the color mode on the server will still mismatch. Use ssr: false in dynamic imports, or wrap with ClientOnly.
Fix 7: Migrating from v2 to v3
Key API differences:
// v2 → v3 migration cheatsheet
// ChakraProvider
// v2: <ChakraProvider theme={theme}>
// v3: <ChakraProvider value={system}> (system from createSystem())
// extendTheme
// v2: import { extendTheme } from '@chakra-ui/react'; extendTheme({...})
// v3: import { createSystem, defineConfig } from '@chakra-ui/react'; createSystem(...)
// useColorModeValue
// v2: useColorModeValue('light-value', 'dark-value')
// v3: Same hook exists, but dark mode is now managed via next-themes
// Stack spacing → gap
// v2: <Stack spacing={4}>
// v3: <Stack gap={4}> (spacing still works as alias)
// isLoading → loading
// v2: <Button isLoading>
// v3: <Button loading> (isLoading still accepted)
// @chakra-ui/icons → removed in v3
// v3: Use lucide-react or react-icons directly
// npm install lucide-react
import { Loader2 } from 'lucide-react';Fix 8: Chakra UI vs Mantine vs Radix UI vs HeadlessUI vs shadcn/ui
The error you’re hitting often signals you’re using the wrong tool for the job. Each library makes a different bet on the design-system-versus-primitive spectrum.
Chakra UI is a full design system. You get styled components out of the box with a token-based theme, dark mode, focus management, and accessibility. The runtime cost is the largest of any option on this list — every component is wrapped in Emotion, every prop is processed through the style engine, and the v3 system object is large. If you want to ship a button with a brand color in five lines, Chakra is the fastest. If you want a sub-50KB bundle, it is not.
Mantine sits in the same design-system slot as Chakra but uses CSS Modules and PostCSS rather than a runtime CSS-in-JS engine. That means smaller production bundles and faster server rendering, with the trade-off that custom theming is less dynamic — you can’t compute styles from props at render time the way Chakra does. Mantine v7+ ships a fully static stylesheet, so it works in React Server Components without the 'use client' boundary Chakra requires.
Radix UI is the opposite philosophy: unstyled, accessible primitives. You get a Dialog that handles focus trapping, scroll locking, and ARIA correctly, but you bring your own CSS. Radix is what powers shadcn/ui under the hood. Pick Radix when you have a designer producing pixel-perfect Figma and need full styling control.
HeadlessUI (from the Tailwind team) is similar to Radix in philosophy — unstyled accessible components — but with a smaller catalog (Menu, Dialog, Listbox, Combobox, Disclosure, Tabs, Switch). The native pairing is Tailwind CSS. Pick HeadlessUI when you’re already using Tailwind and only need the common interactive widgets.
shadcn/ui is not a package — it’s a copy-paste collection of Radix-based components styled with Tailwind. The components live in your repo, not in node_modules. That removes upgrade pain and bundle-size questions, at the cost of the components becoming your code to maintain.
Rule of thumb: pick Chakra or Mantine when you want to ship a working UI without thinking about CSS. Pick Radix or HeadlessUI when you have a design system already. Pick shadcn when you want primitives plus a starting style you can fully edit. Migrating off Chakra later is non-trivial because the props (bg, colorScheme) are non-standard — budget for a rewrite rather than a swap.
Still Not Working?
“useChakra must be used within a ChakraProvider” — the provider isn’t wrapping the component. In Next.js App Router, ChakraProvider must be in a 'use client' component. Check that your providers.tsx has 'use client' at the top and that app/layout.tsx wraps children with it.
Styles not applied at all — you may have a v2/v3 version mismatch. Run npm ls @chakra-ui/react to check the installed version. If you’re following v3 docs but have v2 installed (or vice versa), the APIs won’t match.
Dark mode toggle fires but nothing changes — in v3, dark mode requires next-themes and the ColorModeProvider wrapper. In v2, you need ColorModeScript in _document.tsx and initialColorMode in your theme config.
Flash of unstyled content (FOUC) — for v2 with Pages Router, add <ColorModeScript /> to pages/_document.tsx. For App Router (v2 or v3), ensure the provider renders before any page content.
@chakra-ui/icons not found — this package was removed in Chakra UI v3. Use lucide-react or react-icons instead, which are lighter and more maintained.
framer-motion peer dependency warnings — v3 dropped framer-motion as a required peer. If npm ls framer-motion shows it installed from an old @chakra-ui/react resolution, remove it explicitly and reinstall. Stale peers cause silent animation downgrades on Modal and Drawer.
Production styles missing on Cloudflare Pages or Vercel Edge — Chakra’s Emotion runtime needs Node.js APIs that Edge runtimes do not provide. If you deploy to an Edge target, mark the route as runtime = 'nodejs' or move Chakra-rendering pages off Edge entirely. The symptom is unstyled HTML in production despite working locally.
TypeScript errors after upgrade to v3 — v3 removed theme.ts and extendTheme in favor of createSystem. The Theme type no longer exists. Run a codemod: npx chakra-ui-cli@latest migrate to surface the call sites that need rewriting, then update one by one.
For related component library issues, see Fix: Radix UI Not Working, Fix: Shadcn UI Not Working, Fix: Mantine Not Working, and Fix: Tailwind v4 Not Working.
Solo developer based in Japan. Every solution is cross-referenced with official documentation and tested before publishing.
Was this article helpful?
Related Articles
Fix: Clerk Not Working — Auth Not Loading, Middleware Blocking, or User Data Missing
How to fix Clerk authentication issues — ClerkProvider setup, middleware configuration, useUser and useAuth hooks, server-side auth, webhook handling, and organization features.
Fix: Fumadocs Not Working — Pages Not Found, Search Not Indexing, or MDX Components Missing
How to fix Fumadocs documentation framework issues — Next.js App Router setup, content source configuration, sidebar generation, MDX components, search, OpenAPI integration, and custom themes.
Fix: next-safe-action Not Working — Action Not Executing, Validation Errors Missing, or Type Errors
How to fix next-safe-action issues — action client setup, Zod schema validation, useAction and useOptimisticAction hooks, middleware, error handling, and authorization patterns.
Fix: Nextra Not Working — Pages Not Rendering, Sidebar Missing, or MDX Components Broken
How to fix Nextra documentation site issues — Next.js integration, _meta.json sidebar configuration, custom MDX components, search setup, theme customization, and static export.