Fix: Mantine Not Working — Styles Not Loading, Theme Not Applying, or Components Broken After Upgrade
Quick Answer
How to fix Mantine UI issues — MantineProvider setup, PostCSS configuration, theme customization, dark mode, form validation with useForm, and Next.js App Router integration.
The Problem
Mantine components render but have no styles:
import { Button } from '@mantine/core';
function App() {
return <Button>Click me</Button>;
// Renders an unstyled HTML button
}Or the theme colors don’t match what you configured:
<MantineProvider theme={{ primaryColor: 'violet' }}>
<Button>Should be violet</Button>
</MantineProvider>
// Button is still blueOr after upgrading to Mantine v7, everything breaks:
Module not found: Can't resolve '@mantine/core/styles.css'Why This Happens
Mantine v7 made significant changes to how styles are loaded. Unlike v6 which used CSS-in-JS (emotion), v7 uses native CSS with PostCSS:
- CSS must be explicitly imported —
@mantine/core/styles.cssmust be imported in your app’s entry point. Without it, components render without any styles. This is the biggest change from v6. MantineProvideris required — the theme context provides colors, fonts, spacing, and other tokens to all components. Without it, components use raw defaults.- PostCSS with
postcss-preset-mantineis required — Mantine v7 uses CSS modules and needs a specific PostCSS configuration for features likelight-dark()function and responsive styles. - v6 to v7 is a breaking change — emotion-based styles,
createStyles,sxprop, andstylesprop format all changed. The migration is not backward-compatible.
Fix 1: Setup Mantine v7
npm install @mantine/core @mantine/hooks
npm install -D postcss postcss-preset-mantine postcss-simple-vars// postcss.config.mjs — required for Mantine v7
export default {
plugins: {
'postcss-preset-mantine': {},
'postcss-simple-vars': {
variables: {
'mantine-breakpoint-xs': '36em',
'mantine-breakpoint-sm': '48em',
'mantine-breakpoint-md': '62em',
'mantine-breakpoint-lg': '75em',
'mantine-breakpoint-xl': '88em',
},
},
},
};// app/layout.tsx — Next.js App Router
import '@mantine/core/styles.css';
// Optional: additional module styles
// import '@mantine/dates/styles.css';
// import '@mantine/notifications/styles.css';
// import '@mantine/code-highlight/styles.css';
// import '@mantine/carousel/styles.css';
import { MantineProvider, ColorSchemeScript, createTheme } from '@mantine/core';
const theme = createTheme({
primaryColor: 'blue',
fontFamily: 'Inter, sans-serif',
defaultRadius: 'md',
});
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en" suppressHydrationWarning>
<head>
<ColorSchemeScript defaultColorScheme="auto" />
</head>
<body>
<MantineProvider theme={theme} defaultColorScheme="auto">
{children}
</MantineProvider>
</body>
</html>
);
}Fix 2: Theme Customization
import { createTheme, MantineProvider, virtualColor } from '@mantine/core';
const theme = createTheme({
// Colors — define custom color scales
colors: {
brand: [
'#f0f4ff', '#dbe4ff', '#bac8ff', '#91a7ff', '#748ffc',
'#5c7cfa', '#4c6ef5', '#4263eb', '#3b5bdb', '#364fc7',
],
// Virtual color — maps to different scales in light/dark mode
surface: virtualColor({
name: 'surface',
dark: 'dark',
light: 'gray',
}),
},
primaryColor: 'brand',
primaryShade: { light: 6, dark: 7 },
// Typography
fontFamily: 'Inter, -apple-system, sans-serif',
fontFamilyMonospace: 'Fira Code, monospace',
headings: {
fontFamily: 'Cal Sans, sans-serif',
fontWeight: '700',
sizes: {
h1: { fontSize: '2.5rem', lineHeight: '1.2' },
h2: { fontSize: '2rem', lineHeight: '1.3' },
h3: { fontSize: '1.5rem', lineHeight: '1.4' },
},
},
// Spacing and radius
defaultRadius: 'md',
spacing: { xs: '0.5rem', sm: '0.75rem', md: '1rem', lg: '1.5rem', xl: '2rem' },
// Component defaults
components: {
Button: {
defaultProps: {
size: 'md',
variant: 'filled',
},
styles: {
root: {
fontWeight: 600,
},
},
},
Input: {
defaultProps: {
size: 'md',
},
},
Card: {
defaultProps: {
shadow: 'sm',
padding: 'lg',
withBorder: true,
},
},
},
});Fix 3: Common Components
import {
Button, TextInput, Select, Checkbox, Group, Stack, Card, Text,
Title, Badge, Avatar, Tabs, Accordion, Modal, Drawer,
AppShell, Burger, NavLink,
} from '@mantine/core';
import { useDisclosure } from '@mantine/hooks';
// Layout with AppShell
function DashboardLayout({ children }: { children: React.ReactNode }) {
const [opened, { toggle }] = useDisclosure();
return (
<AppShell
header={{ height: 60 }}
navbar={{ width: 250, breakpoint: 'sm', collapsed: { mobile: !opened } }}
padding="md"
>
<AppShell.Header>
<Group h="100%" px="md">
<Burger opened={opened} onClick={toggle} hiddenFrom="sm" size="sm" />
<Title order={3}>My App</Title>
</Group>
</AppShell.Header>
<AppShell.Navbar p="md">
<NavLink label="Dashboard" href="/dashboard" active />
<NavLink label="Settings" href="/settings" />
<NavLink label="Users" href="/users" />
</AppShell.Navbar>
<AppShell.Main>{children}</AppShell.Main>
</AppShell>
);
}
// Card list
function UserCard({ user }: { user: User }) {
return (
<Card>
<Group>
<Avatar src={user.avatar} radius="xl" size="lg" />
<div>
<Text fw={600}>{user.name}</Text>
<Text size="sm" c="dimmed">{user.email}</Text>
</div>
<Badge ml="auto" color={user.role === 'admin' ? 'red' : 'blue'}>
{user.role}
</Badge>
</Group>
</Card>
);
}
// Modal
function ConfirmModal() {
const [opened, { open, close }] = useDisclosure(false);
return (
<>
<Modal opened={opened} onClose={close} title="Confirm Action" centered>
<Text>Are you sure you want to proceed?</Text>
<Group mt="md" justify="flex-end">
<Button variant="default" onClick={close}>Cancel</Button>
<Button color="red" onClick={() => { handleDelete(); close(); }}>Delete</Button>
</Group>
</Modal>
<Button color="red" onClick={open}>Delete Item</Button>
</>
);
}Fix 4: Forms with @mantine/form
npm install @mantine/formimport { useForm, zodResolver } from '@mantine/form';
import { TextInput, NumberInput, Select, Checkbox, Button, Stack } from '@mantine/core';
import { z } from 'zod';
const schema = z.object({
name: z.string().min(2, 'Name must be at least 2 characters'),
email: z.string().email('Invalid email'),
age: z.number().min(18, 'Must be 18+').max(150),
role: z.string().min(1, 'Select a role'),
terms: z.boolean().refine(v => v, 'Must accept terms'),
});
function RegistrationForm() {
const form = useForm({
mode: 'uncontrolled',
initialValues: {
name: '',
email: '',
age: 18,
role: '',
terms: false,
},
validate: zodResolver(schema),
});
function handleSubmit(values: typeof form.values) {
console.log(values);
}
return (
<form onSubmit={form.onSubmit(handleSubmit)}>
<Stack>
<TextInput
label="Name"
placeholder="Your name"
withAsterisk
key={form.key('name')}
{...form.getInputProps('name')}
/>
<TextInput
label="Email"
placeholder="[email protected]"
withAsterisk
key={form.key('email')}
{...form.getInputProps('email')}
/>
<NumberInput
label="Age"
withAsterisk
min={0}
max={150}
key={form.key('age')}
{...form.getInputProps('age')}
/>
<Select
label="Role"
placeholder="Select role"
withAsterisk
data={[
{ value: 'developer', label: 'Developer' },
{ value: 'designer', label: 'Designer' },
{ value: 'manager', label: 'Manager' },
]}
key={form.key('role')}
{...form.getInputProps('role')}
/>
<Checkbox
label="I accept the terms and conditions"
key={form.key('terms')}
{...form.getInputProps('terms', { type: 'checkbox' })}
/>
<Button type="submit">Register</Button>
</Stack>
</form>
);
}Fix 5: Dark Mode
// Toggle color scheme
'use client';
import { useMantineColorScheme, ActionIcon, Group } from '@mantine/core';
function ColorSchemeToggle() {
const { colorScheme, setColorScheme } = useMantineColorScheme();
return (
<Group>
<ActionIcon
onClick={() => setColorScheme('light')}
variant={colorScheme === 'light' ? 'filled' : 'default'}
>
☀️
</ActionIcon>
<ActionIcon
onClick={() => setColorScheme('dark')}
variant={colorScheme === 'dark' ? 'filled' : 'default'}
>
🌙
</ActionIcon>
<ActionIcon
onClick={() => setColorScheme('auto')}
variant={colorScheme === 'auto' ? 'filled' : 'default'}
>
💻
</ActionIcon>
</Group>
);
}
// CSS module with light-dark() — requires postcss-preset-mantine
// styles.module.css
/*
.card {
background-color: light-dark(var(--mantine-color-white), var(--mantine-color-dark-6));
color: light-dark(var(--mantine-color-black), var(--mantine-color-white));
border: 1px solid light-dark(var(--mantine-color-gray-3), var(--mantine-color-dark-4));
}
*/Fix 6: Notifications
npm install @mantine/notifications// app/layout.tsx — add Notifications provider
import '@mantine/notifications/styles.css';
import { Notifications } from '@mantine/notifications';
<MantineProvider>
<Notifications position="top-right" />
{children}
</MantineProvider>// Usage anywhere
import { notifications } from '@mantine/notifications';
function SaveButton() {
async function handleSave() {
const id = notifications.show({
loading: true,
title: 'Saving...',
message: 'Please wait',
autoClose: false,
});
try {
await saveData();
notifications.update({
id,
loading: false,
title: 'Saved!',
message: 'Your changes have been saved',
color: 'green',
autoClose: 3000,
});
} catch {
notifications.update({
id,
loading: false,
title: 'Error',
message: 'Failed to save',
color: 'red',
autoClose: 5000,
});
}
}
return <Button onClick={handleSave}>Save</Button>;
}Still Not Working?
Components have no styles — import @mantine/core/styles.css in your root layout or entry file. This is required in Mantine v7. Each additional package needs its own CSS import (@mantine/dates/styles.css, etc.).
PostCSS errors or light-dark() not working — install postcss-preset-mantine and postcss-simple-vars, then add them to postcss.config.mjs. Without the preset, Mantine’s CSS features like light-dark() don’t compile.
v6 code doesn’t work in v7 — createStyles, sx prop, and emotion-based styles prop were removed in v7. Replace createStyles with CSS modules, sx with style or className, and update styles to use the new format. See the official v6→v7 migration guide.
ColorSchemeScript causes hydration errors — put <ColorSchemeScript /> in <head>, not <body>. Add suppressHydrationWarning to the <html> tag. The script must run before React hydrates to prevent a flash of wrong color scheme.
For related UI component issues, see Fix: shadcn/ui Not Working and Fix: Radix UI 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: cmdk Not Working — Command Palette Not Opening, Items Not Filtering, or Keyboard Navigation Broken
How to fix cmdk command palette issues — Dialog setup, custom filtering, groups and separators, keyboard shortcuts, async search, nested pages, and integration with shadcn/ui and Tailwind.
Fix: Conform Not Working — Form Validation Not Triggering, Server Errors Missing, or Zod Schema Rejected
How to fix Conform form validation issues — useForm setup with Zod, server action integration, nested and array fields, file uploads, progressive enhancement, and Remix and Next.js usage.
Fix: i18next Not Working — Translations Missing, Language Not Switching, or Namespace Errors
How to fix i18next issues — react-i18next setup, translation file loading, namespace configuration, language detection, interpolation, pluralization, and Next.js integration.
Fix: Lingui Not Working — Messages Not Extracted, Translations Missing, or Macro Errors
How to fix Lingui.js i18n issues — setup with React, message extraction, macro compilation, ICU format, lazy loading catalogs, and Next.js integration.