9.8 KiB
9.8 KiB
Styling & Theming Reference
Mantine styling: MantineProvider, theme object, CSS modules, style props, and Styles API.
MantineProvider
Required wrapper for all Mantine components:
import { createTheme, MantineProvider } from '@mantine/core';
const theme = createTheme({
primaryColor: 'blue',
fontFamily: 'Inter, sans-serif',
});
function App() {
return (
<MantineProvider theme={theme}>
{/* App content */}
</MantineProvider>
);
}
Key Props
| Prop | Type | Default | Description |
|---|---|---|---|
theme |
MantineThemeOverride |
- | Theme customization |
defaultColorScheme |
'light' | 'dark' | 'auto' |
'light' |
Default color scheme |
forceColorScheme |
'light' | 'dark' |
- | Force specific scheme |
env |
'default' | 'test' |
'default' |
Disable transitions for tests |
Theme Object
import { createTheme, rem } from '@mantine/core';
const theme = createTheme({
// Colors
primaryColor: 'blue',
primaryShade: { light: 6, dark: 8 },
// Typography
fontFamily: 'Inter, sans-serif',
headings: {
fontFamily: 'Greycliff CF, sans-serif',
fontWeight: '700',
},
// Spacing & Sizing
spacing: { xs: rem(10), sm: rem(12), md: rem(16), lg: rem(20), xl: rem(32) },
radius: { xs: rem(2), sm: rem(4), md: rem(8), lg: rem(16), xl: rem(32) },
// Defaults
defaultRadius: 'md',
cursorType: 'pointer',
respectReducedMotion: true,
});
Custom Colors
import { createTheme, MantineColorsTuple } from '@mantine/core';
const brand: MantineColorsTuple = [
'#f0f9ff', '#e0f2fe', '#bae6fd', '#7dd3fc', '#38bdf8',
'#0ea5e9', '#0284c7', '#0369a1', '#075985', '#0c4a6e',
];
const theme = createTheme({
colors: { brand },
primaryColor: 'brand',
});
Color Scheme (Dark Mode)
import { useMantineColorScheme, useComputedColorScheme } from '@mantine/core';
function ColorSchemeToggle() {
const { setColorScheme, toggleColorScheme } = useMantineColorScheme();
const computed = useComputedColorScheme('light'); // Resolved value
return (
<>
<Button onClick={() => setColorScheme('light')}>Light</Button>
<Button onClick={() => setColorScheme('dark')}>Dark</Button>
<Button onClick={toggleColorScheme}>Toggle</Button>
</>
);
}
// SSR: Prevent flash of wrong color scheme
import { ColorSchemeScript, mantineHtmlProps } from '@mantine/core';
<html {...mantineHtmlProps}>
<head>
<ColorSchemeScript defaultColorScheme="auto" />
</head>
</html>
Style Props
All components accept style props for quick styling:
import { Box, Text, Button } from '@mantine/core';
function Demo() {
return (
<Box
p="md" // padding
m="lg" // margin
mt="xl" // margin-top
bg="blue.6" // background (color.shade)
c="white" // color
w={200} // width (number = px)
h="100%" // height
maw={500} // max-width
pos="relative" // position
ta="center" // text-align
fz="sm" // font-size
fw={700} // font-weight
ff="monospace" // font-family
lh={1.5} // line-height
style={{ borderRadius: 'var(--mantine-radius-md)' }}
>
<Text c="dimmed" fz="xs" tt="uppercase">
Uppercase dimmed text
</Text>
</Box>
);
}
Common Style Props
| Prop | CSS Property | Example |
|---|---|---|
m, mx, my, mt, mr, mb, ml |
margin | m="md", mt={20} |
p, px, py, pt, pr, pb, pl |
padding | p="lg" |
w, h, maw, mah, miw, mih |
width, height, max/min | w="100%" |
c |
color | c="blue.6", c="dimmed" |
bg |
background-color | bg="gray.1" |
fz |
font-size | fz="sm", fz={14} |
fw |
font-weight | fw={500}, fw="bold" |
ta |
text-align | ta="center" |
td |
text-decoration | td="underline" |
tt |
text-transform | tt="uppercase" |
ff |
font-family | ff="monospace" |
lh |
line-height | lh={1.5} |
pos |
position | pos="absolute" |
top, left, right, bottom |
position offsets | top={10} |
display |
display | display="flex" |
opacity |
opacity | opacity={0.5} |
Responsive Props
<Box
w={{ base: '100%', sm: '50%', md: 400 }}
p={{ base: 'xs', md: 'xl' }}
display={{ base: 'none', md: 'block' }}
>
Responsive box
</Box>
CSS Modules
Recommended styling approach. Create .module.css files:
/* Button.module.css */
.root {
background-color: var(--mantine-color-blue-6);
@mixin hover {
background-color: var(--mantine-color-blue-7);
}
/* Responsive */
@mixin smaller-than sm {
font-size: var(--mantine-font-size-xs);
}
@mixin larger-than md {
padding: var(--mantine-spacing-xl);
}
/* Dark mode */
@mixin dark {
background-color: var(--mantine-color-blue-8);
}
@mixin light {
background-color: var(--mantine-color-blue-4);
}
}
.label {
color: var(--mantine-color-white);
}
import { Button } from '@mantine/core';
import classes from './Button.module.css';
function Demo() {
return (
<Button classNames={classes}>
Styled button
</Button>
);
}
PostCSS Preset
postcss-preset-mantine provides:
Mixins
/* Hover state */
@mixin hover {
/* Hover-only styles */
}
/* Responsive breakpoints */
@mixin smaller-than sm { }
@mixin larger-than md { }
/* Color scheme */
@mixin light { }
@mixin dark { }
/* RTL support */
@mixin rtl { }
@mixin ltr { }
Functions
.element {
/* rem() - convert to rem */
font-size: rem(16px); /* 1rem */
/* em() - convert to em */
padding: em(24px); /* 1.5em */
/* light-dark() - color scheme values */
background: light-dark(white, black);
/* alpha() - add opacity to color */
background: alpha(var(--mantine-color-blue-5), 0.5);
}
Styles API
Override internal component styles:
classNames Prop
import { TextInput } from '@mantine/core';
import classes from './TextInput.module.css';
// CSS module with selectors matching Styles API
// .root, .input, .label, .error, etc.
<TextInput
classNames={{
root: classes.root,
input: classes.input,
label: classes.label,
}}
/>
styles Prop (CSS-in-JS)
<TextInput
styles={{
root: { marginBottom: 20 },
input: { backgroundColor: 'var(--mantine-color-gray-0)' },
label: { fontWeight: 700 },
}}
/>
styles Function
<TextInput
styles={(theme, props) => ({
input: {
borderColor: props.error
? theme.colors.red[6]
: theme.colors.gray[4],
},
})}
/>
Finding Selectors
All Styles API selectors are documented for each component. Common patterns:
root- Root elementlabel- Label textinput- Input elementwrapper- Input wrappererror- Error messagedescription- Description textrequired- Required asterisksection- Input sections (left/right icons)
hiddenFrom / visibleFrom
Hide/show at breakpoints:
import { Text } from '@mantine/core';
<Text hiddenFrom="sm">Hidden on sm and larger</Text>
<Text visibleFrom="md">Visible only on md and larger</Text>
lightHidden / darkHidden
Hide based on color scheme:
<Text lightHidden>Only in dark mode</Text>
<Text darkHidden>Only in light mode</Text>
Box Component
Base component for custom styling:
import { Box } from '@mantine/core';
<Box
component="section" // Render as different element
className={classes.wrapper}
p="md"
bg="gray.1"
style={{ borderRadius: 'var(--mantine-radius-md)' }}
>
Content
</Box>
Polymorphic Components
Many components accept component prop:
import { Button } from '@mantine/core';
import { Link } from 'react-router-dom';
// Render Button as Link
<Button component={Link} to="/about">
About
</Button>
// Render as native anchor
<Button component="a" href="https://example.com">
External
</Button>
CSS Variables in Styles
Access theme values:
<Box
style={{
backgroundColor: 'var(--mantine-color-blue-6)',
padding: 'var(--mantine-spacing-md)',
borderRadius: 'var(--mantine-radius-sm)',
boxShadow: 'var(--mantine-shadow-md)',
}}
>
Styled with CSS variables
</Box>
Global Styles
// In your CSS
:root {
--my-custom-color: #ff6b6b;
}
/* Target Mantine root element */
[data-mantine-color-scheme="dark"] {
--my-custom-color: #ff8787;
}
/* Global component overrides */
.mantine-Button-root {
font-weight: 600;
}
rem() and em() Utilities
import { rem, em } from '@mantine/core';
// In styles or inline
<Box style={{ fontSize: rem(16), padding: rem(24) }} />
// rem(16) => '1rem'
// em(24) => '1.5em'
Style Props vs CSS Modules
| Use Case | Recommended |
|---|---|
| Quick prototyping | Style props |
| Simple spacing/colors | Style props |
| Complex hover/focus states | CSS modules |
| Responsive layouts | CSS modules |
| Reusable component styles | CSS modules |
| Performance critical | CSS modules |
Component Default Props (Theme)
Override defaults globally:
const theme = createTheme({
components: {
Button: Button.extend({
defaultProps: { variant: 'outline', size: 'md', radius: 'xl' },
}),
TextInput: TextInput.extend({
defaultProps: { size: 'md' },
classNames: { root: 'my-input-root', input: 'my-input' },
}),
},
});
CSS Variables Reference
--mantine-color-{color}-{shade} // Colors (0-9)
--mantine-primary-color-{shade} // Primary color
--mantine-spacing-{size} // xs, sm, md, lg, xl
--mantine-radius-{size} // xs, sm, md, lg, xl
--mantine-font-family // Main font
--mantine-font-size-{size} // xs, sm, md, lg, xl
--mantine-breakpoint-{size} // Responsive breakpoints