Mantine v7 Component Patterns
Quick Guide: Mantine v7 is a full-featured React component library using CSS Modules (not CSS-in-JS). Wrap your app inMantineProviderwith acreateThemeobject. Style with CSS Modules + PostCSS preset mixins, the Styles API (classNames/stylesprops), or style props (p,m,bg, etc.). Use@mantine/formfor form management,@mantine/hooksfor utility hooks, and@mantine/notificationsfor toasts. PostCSS preset withpostcss-preset-mantineis required for responsive mixins andlight-dark().
<critical_requirements>
CRITICAL: Before Using This Skill
All code must follow project conventions in CLAUDE.md (kebab-case, named exports, import ordering, import type, named constants)
(You MUST wrap your app in MantineProvider and import @mantine/core/styles.css at the root)
(You MUST install and configure postcss-preset-mantine for CSS Modules mixins and responsive utilities)
(You MUST use CSS Modules (.module.css) for custom component styles - createStyles was removed in v7)
(You MUST provide 10-shade color tuples when adding custom colors to the theme)
</critical_requirements>
Auto-detection: Mantine, @mantine/core, @mantine/hooks, @mantine/form, @mantine/notifications, @mantine/dates, MantineProvider, createTheme, useForm, useDisclosure, useDebouncedValue, useMediaQuery, postcss-preset-mantine, light-dark(), getInputProps, classNames prop, styles prop
When to use:
- Building React applications needing 100+ ready-to-use accessible components
- Projects requiring built-in form management, date pickers, or notification systems
- Applications where CSS Modules (no runtime CSS-in-JS) are preferred for performance
- Teams wanting a batteries-included library with hooks, theming, and responsive utilities
When NOT to use:
- Projects committed to a different component library
- Applications requiring utility-class-first styling (Mantine uses CSS Modules)
- When only a few components are needed and a full library is overkill
Key patterns covered:
- MantineProvider setup with createTheme and PostCSS configuration
- Core components (Button, TextInput, Select, Modal, Drawer, Menu, Tabs, Accordion)
- Styling with CSS Modules, Styles API (classNames/styles/vars), and style props
- Theming with createTheme (colors, defaultRadius, component defaults)
- Color scheme (light/dark/auto) with useMantineColorScheme
- @mantine/form (useForm, validation, nested fields, list management)
- @mantine/hooks (useDisclosure, useDebouncedValue, useMediaQuery)
- @mantine/notifications and @mantine/dates
<philosophy>
Philosophy
Mantine is a batteries-included React component library. Unlike copy-and-own systems, Mantine provides pre-built components that are styled via CSS Modules and customized through a theme object and Styles API. The v7 rewrite (late 2023) dropped Emotion for native CSS Modules, eliminating CSS-in-JS runtime overhead entirely.
What Mantine handles vs what other skills handle:
- Mantine: component rendering, theming, form management, hooks, notifications, dates
- Your styling approach: custom CSS beyond Mantine's Styles API
- Your data fetching solution: server state management
- Your state management solution: global client state beyond component state
</philosophy>
<patterns>
Core Patterns
Pattern 1: MantineProvider Setup
Every Mantine app requires MantineProvider at the root with CSS imports and PostCSS configuration.
// app.tsx
import "@mantine/core/styles.css";
// Import additional package styles only if using those packages:
// import '@mantine/dates/styles.css';
// import '@mantine/notifications/styles.css';
import { createTheme, MantineProvider } from "@mantine/core";
const theme = createTheme({
primaryColor: "blue",
defaultRadius: "md",
});
export function App() {
return (
<MantineProvider theme={theme}>{/* Your app content */}</MantineProvider>
);
}
PostCSS Configuration
// postcss.config.cjs
module.exports = {
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",
},
},
},
};
SSR Setup (Required for SSR Frameworks)
import { ColorSchemeScript, mantineHtmlProps } from "@mantine/core";
// In your root HTML/layout:
<html lang="en" {...mantineHtmlProps}>
<head>
<ColorSchemeScript defaultColorScheme="auto" />
</head>
<body>
<App />
</body>
</html>;
Why good: Theme object lives outside component body (prevents re-renders), PostCSS preset enables responsive mixins, ColorSchemeScript prevents flash of wrong theme on SSR
Pattern 2: Core Components
Mantine components accept className, style, style props, and the Styles API. All support variant, size, color, and radius props.
import {
Button,
TextInput,
Select,
Checkbox,
Group,
Stack,
} from "@mantine/core";
// Button with variants and sizes
<Button variant="filled" color="blue" size="md" loading={isLoading}>
Submit
</Button>
<Button variant="outline">Cancel</Button>
<Button variant="light" color="red" leftSection={<TrashIcon />}>
Delete
</Button>
// Text inputs
<TextInput
label="Email"
placeholder="you@example.com"
withAsterisk
error={errors.email}
/>
// Select
<Select
label="Role"
data={["Admin", "Editor", "Viewer"]}
placeholder="Pick a role"
searchable
clearable
/>
// Checkbox
<Checkbox label="Accept terms" checked={accepted} onChange={handleChange} />
// Layout components
<Group gap="md">{/* Horizontal flex */}</Group>
<Stack gap="sm">{/* Vertical flex */}</Stack>
Why good: Consistent API across all components (variant, size, color, radius), layout components (Group, Stack) replace manual flexbox
Pattern 3: Modal, Drawer, Menu, Tabs, Accordion
Overlay and compound components use useDisclosure for state management.
import { Modal, Button } from "@mantine/core";
import { useDisclosure } from "@mantine/hooks";
function Demo() {
const [opened, { open, close }] = useDisclosure(false);
return (
<>
<Modal opened={opened} onClose={close} title="Confirm Action">
<p>Are you sure?</p>
<Group mt="md" justify="flex-end">
<Button variant="outline" onClick={close}>
Cancel
</Button>
<Button onClick={handleConfirm}>Confirm</Button>
</Group>
</Modal>
<Button onClick={open}>Open Modal</Button>
</>
);
}
// Drawer - same pattern as Modal
import { Drawer } from "@mantine/core";
<Drawer opened={opened} onClose={close} title="Settings" position="right">
{/* Drawer content */}
</Drawer>;
// Menu
import { Menu, Button } from "@mantine/core";
<Menu shadow="md" width={200}>
<Menu.Target>
<Button>Actions</Button>
</Menu.Target>
<Menu.Dropdown>
<Menu.Label>Application</Menu.Label>
<Menu.Item leftSection={<SettingsIcon />}>Settings</Menu.Item>
<Menu.Divider />
<Menu.Item color="red" leftSection={<TrashIcon />}>
Delete
</Menu.Item>
</Menu.Dropdown>
</Menu>;
// Tabs
import { Tabs } from "@mantine/core";
<Tabs defaultValue="general">
<Tabs.List>
<Tabs.Tab value="general">General</Tabs.Tab>
<Tabs.Tab value="security">Security</Tabs.Tab>
</Tabs.List>
<Tabs.Panel value="general">General settings...</Tabs.Panel>
<Tabs.Panel value="security">Security settings...</Tabs.Panel>
</Tabs>;
// Accordion
import { Accordion } from "@mantine/core";
<Accordion>
<Accordion.Item value="faq-1">
<Accordion.Control>How does billing work?</Accordion.Control>
<Accordion.Panel>Monthly billing starts on signup date.</Accordion.Panel>
</Accordi