---
name: mantine
description: Builds React applications with Mantine's 100+ components, hooks, and form library. Use when creating feature-rich UIs with built-in dark mode, accessibility, and TypeScript support.
---
# Mantine
Full-featured React component library with 100+ customizable components and 50+ hooks.
## Quick Start
```bash
npm install @mantine/core @mantine/hooks
npm install -D postcss postcss-preset-mantine postcss-simple-vars
```
```js
// 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',
},
},
},
};
```
```tsx
// App.tsx
import '@mantine/core/styles.css';
import { MantineProvider, createTheme } from '@mantine/core';
const theme = createTheme({
primaryColor: 'blue',
fontFamily: 'Inter, sans-serif',
});
function App() {
return (
);
}
```
```tsx
// Usage
import { Button, TextInput, Group, Stack } from '@mantine/core';
function Demo() {
return (
);
}
```
## Core Components
### Button
```tsx
import { Button, ActionIcon } from '@mantine/core';
import { IconSettings } from '@tabler/icons-react';
// Variants
// Sizes
// Colors
// With icons
}>Settings
}>Next
// Loading
// Icon button
```
### TextInput
```tsx
import { TextInput, PasswordInput, Textarea, NumberInput } from '@mantine/core';
```
### Select and MultiSelect
```tsx
import { Select, MultiSelect, Combobox } from '@mantine/core';
```
### Modal and Drawer
```tsx
import { Modal, Button } from '@mantine/core';
import { useDisclosure } from '@mantine/hooks';
function ModalDemo() {
const [opened, { open, close }] = useDisclosure(false);
return (
<>
Modal content here...
>
);
}
// Drawer
import { Drawer } from '@mantine/core';
Drawer content...
```
### Notifications
```bash
npm install @mantine/notifications
```
```tsx
import '@mantine/notifications/styles.css';
import { Notifications, notifications } from '@mantine/notifications';
// Add to app root
// Show notification
notifications.show({
title: 'Success',
message: 'Your changes have been saved',
color: 'green',
autoClose: 5000,
});
// Update existing notification
const id = notifications.show({
loading: true,
title: 'Loading...',
message: 'Please wait',
autoClose: false,
});
notifications.update({
id,
loading: false,
title: 'Complete',
message: 'Data loaded successfully',
color: 'green',
autoClose: 3000,
});
```
### Tabs
```tsx
import { Tabs } from '@mantine/core';
Gallery
Messages
Settings
Gallery content
Messages content
Settings content
```
### Card
```tsx
import { Card, Image, Text, Badge, Button, Group } from '@mantine/core';
Product Name
On Sale
Product description goes here.
```
## Forms
```bash
npm install @mantine/form
```
```tsx
import { useForm } from '@mantine/form';
import { TextInput, Button, Stack } from '@mantine/core';
function ContactForm() {
const form = useForm({
mode: 'uncontrolled',
initialValues: {
name: '',
email: '',
message: '',
},
validate: {
name: (value) => value.length < 2 ? 'Name is too short' : null,
email: (value) => /^\S+@\S+$/.test(value) ? null : 'Invalid email',
message: (value) => value.length < 10 ? 'Message too short' : null,
},
});
return (
);
}
```
### Form with Zod Validation
```tsx
import { useForm, zodResolver } from '@mantine/form';
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 or older'),
});
const form = useForm({
mode: 'uncontrolled',
initialValues: { name: '', email: '', age: 18 },
validate: zodResolver(schema),
});
```
## Hooks
```tsx
import {
useDisclosure,
useToggle,
useDebouncedValue,
useClipboard,
useLocalStorage,
useMediaQuery,
useClickOutside,
useHotkeys,
useForm,
} from '@mantine/hooks';
// Disclosure (modals, menus)
const [opened, { open, close, toggle }] = useDisclosure(false);
// Toggle between values
const [value, toggle] = useToggle(['light', 'dark']);
// Debounced value
const [search, setSearch] = useState('');
const [debounced] = useDebouncedValue(search, 300);
// Clipboard
const clipboard = useClipboard({ timeout: 2000 });
clipboard.copy('Text to copy');
clipboard.copied // true after copy
// Local storage
const [value, setValue] = useLocalStorage({
key: 'user-preference',
defaultValue: 'dark',
});
// Media query
const isMobile = useMediaQuery('(max-width: 768px)');
// Click outside
const ref = useClickOutside(() => setOpened(false));
// Keyboard shortcuts
useHotkeys([
['mod+K', () => openSearch()],
['mod+S', () => saveDocument()],
['Escape', () => closeModal()],
]);
```
## Theming
### Custom Theme
```tsx
import { createTheme, MantineProvider } from '@mantine/core';
const theme = createTheme({
// Primary color
primaryColor: 'brand',
primaryShade: { light: 6, dark: 8 },
// Custom colors (10 shades each)
colors: {
brand: [
'#e6f2ff', '#b3d9ff', '#80bfff', '#4da6ff', '#1a8cff',
'#0073e6', '#005cb3', '#004480', '#002d4d', '#00161a',
],
},
// Typography
fontFamily: 'Inter, sans-serif',
fontFamilyMonospace: 'Fira Code, monospace',
headings: {
fontFamily: 'Inter, sans-serif',
fontWeight: '600',
sizes: {
h1: { fontSize: '2.5rem', lineHeight: '1.2' },
h2: { fontSize: '2rem', lineHeight: '1.3' },
},
},
// Spacing scale
spacing: {
xs: '0.5rem',
sm: '0.75rem',
md: '1rem',
lg: '1.5rem',
xl: '2rem',
},
// Border radius
radius: {
xs: '2px',
sm: '4px',
md: '8px',
lg: '16px',
xl: '32px',
},
defaultRadius: 'md',
// Shadows
shadows: {
xs: '0 1px 2px rgba(0, 0, 0, 0.05)',
sm: '0 1px 3px rgba(0, 0, 0, 0.1)',
md: '0 4px 6px rgba(0, 0, 0, 0.1)',
lg: '0 10px 15px rgba(0, 0, 0, 0.1)',
xl: '0 20px 25px rgba(0, 0, 0, 0.15)',
},
// Focus styles
focusRing: 'auto', // 'auto' | 'always' | 'never'
// Other
cursorType: 'pointer', // 'default' | 'pointer'
autoContrast: true,
});
```
### Dark Mode
```tsx
import { MantineProvider, useMantineColorScheme, Button } from '@mantine/core';
// Provider setup
// Toggle button
function ColorSchemeToggle() {
const { colorScheme, toggleColorScheme } = useMantineColorScheme();
return (
);
}
```
### Styles API
```tsx
import { Button, createStyles } from '@mantine/core';
// Using classNames prop
// Using styles prop
// CSS Modules (recommended)
// Button.module.css
.root {
background-color: var(--mantine-color-blue-6);
}
.label {
font-weight: 700;
}
// Component
import classes from './Button.module.css';
```
### CSS Variables
```tsx
// Access theme tokens via CSS variables
.myComponent {
background-color: var(--mantine-color-blue-6);
padding: var(--mantine-spacing-md);
border-radius: var(--mantine-radius-md);
font-size: var(--mantine-font-size-sm);
/* Dark mode specific */
@mixin dark {
background-color: var(--mantine-color-dark-6);
}
/* Responsive */
@media (max-width: $mantine-breakpoint-sm) {
padding: var(--mantine-spacing-xs);
}
}
```
## Layout
```tsx
import {
AppShell,
Container,
Grid,
Group,
Stack,
Flex,
SimpleGrid,
Center,
} from '@mantine/core';
// App shell layout
Header
Navbar
Content
// Container with max width
Content
// Grid
Half
Half
Responsive
// Simple grid (equal columns)
1
2
3
// Flex layouts
Left
Right
Item 1
Item 2
Item
Item
```
## Best Practices
1. **Use CSS modules** - Most performant styling approach
2. **Leverage hooks** - `useDisclosure`, `useDebouncedValue`, `useForm` for common patterns
3. **Use Styles API** - Override component parts with `classNames` prop
4. **Theme tokens** - Use CSS variables for consistent theming
5. **Form validation** - Use `@mantine/form` with Zod for type-safe forms
## Reference Files
- [references/components.md](references/components.md) - Complete component list
- [references/hooks.md](references/hooks.md) - All available hooks