createStyles

All Mantine components are built with emotion based css-in-js library. We recommend using createStyles to create styles for the rest of your application as it provides the most convenient way to utilize Mantine theme, but it is not required – you can use any other styling tools and languages.

Usage

createStyles demo
import { createStyles } from '@mantine/core';
const useStyles = createStyles((theme, _params, getRef) => ({
wrapper: {
// subscribe to color scheme changes right in your styles
backgroundColor: theme.colorScheme === 'dark' ? theme.colors.dark[5] : theme.colors.gray[1],
maxWidth: 400,
width: '100%',
height: 180,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
marginLeft: 'auto',
marginRight: 'auto',
borderRadius: theme.radius.sm,
// Dynamic media queries, define breakpoints in theme, use anywhere
[`@media (max-width: ${theme.breakpoints.sm}px)`]: {
// Type safe child reference in nested selectors via ref
[`& .${getRef('child')}`]: {
fontSize: theme.fontSizes.xs,
},
},
},
child: {
// assign ref to element
ref: getRef('child'),
backgroundColor: theme.colorScheme === 'dark' ? theme.colors.dark[8] : theme.white,
padding: theme.spacing.md,
borderRadius: theme.radius.sm,
boxShadow: theme.shadows.md,
color: theme.colorScheme === 'dark' ? theme.white : theme.black,
},
}));
function Demo() {
const { classes } = useStyles();
return (
<div className={classes.wrapper}>
<div className={classes.child}>createStyles demo</div>
</div>
);
}

Pseudo-classes

You can add pseudo-classes the same way as in any css-preprocessor like Sass:

import { createStyles } from '@mantine/core';
const useStyles = createStyles((theme) => ({
button: {
color: theme.white,
backgroundColor: theme.colors.blue[6],
border: 0,
borderRadius: theme.radius.md,
padding: `${theme.spacing.sm}px ${theme.spacing.lg}px`,
cursor: 'pointer',
margin: theme.spacing.md,
// Use pseudo-classes just like you would in Sass
'&:hover': {
backgroundColor: theme.colors.blue[9],
},
'&:not(:first-of-type)': {
backgroundColor: theme.colors.violet[6],
// pseudo-classes can be nested
'&:hover': {
backgroundColor: theme.colors.violet[9],
},
},
},
}));
function Demo() {
const { classes } = useStyles();
return (
<div>
<button type="button" className={classes.button}>
First
</button>
<button type="button" className={classes.button}>
Second
</button>
<button type="button" className={classes.button}>
Third
</button>
</div>
);
}

Styles parameters

You can receive any amount of parameters as second argument of createStyles function, latter you will need to pass those parameters as argument to useStyles hook:

import { createStyles } from '@mantine/core';
interface ButtonProps {
color: 'blue' | 'violet';
radius: number;
}
const useStyles = createStyles((theme, { color, radius }: ButtonProps) => ({
button: {
color: theme.white,
backgroundColor: theme.colors[color][6],
borderRadius: radius,
padding: theme.spacing.md,
margin: theme.spacing.md,
border: 0,
cursor: 'pointer',
},
}));
function Button({ color, radius }: ButtonProps) {
const { classes } = useStyles({ color, radius });
return (
<button type="button" className={classes.button}>
{color} button with {radius}px radius
</button>
);
}
function Demo() {
return (
<>
<Button color="blue" radius={5} />
<Button color="violet" radius={50} />
</>
);
}

Composition and nested selectors

Since createStyles produces scoped class names you will need to create a reference to selector in order to get static selector. createStyles receives getRef function to handle static selector creation:

import { createStyles } from '@mantine/core';
const useStyles = createStyles((theme, _params, getRef) => ({
button: {
// assign reference to selector
ref: getRef('button'),
// and add any other properties
backgroundColor: theme.colors.blue[6],
color: theme.white,
padding: `${theme.spacing.sm}px ${theme.spacing.lg}px`,
borderRadius: theme.radius.md,
cursor: 'pointer',
border: 0,
},
container: {
display: 'flex',
justifyContent: 'center',
backgroundColor: theme.colorScheme === 'dark' ? theme.colors.dark[8] : theme.colors.gray[1],
padding: theme.spacing.xl,
// reference button with nested selector
[`&:hover .${getRef('button')}`]: {
backgroundColor: theme.colors.violet[6],
},
},
}));
function Demo() {
const { classes } = useStyles();
return (
<div className={classes.container}>
<button className={classes.button} type="button">
Hover container to change button color
</button>
</div>
);
}

Classes merging (cx function)

To merge class names use cx function, it has the same api as clsx package.

!important: Do not use external libraries like classnames or clsx with class names created with createStyles function as it will produce styles collisions.

import { useState } from 'react';
import { createStyles } from '@mantine/core';
const useStyles = createStyles((theme) => ({
button: {
backgroundColor: theme.colorScheme === 'dark' ? theme.colors.dark[5] : theme.colors.gray[1],
border: 0,
color: theme.colorScheme === 'dark' ? theme.white : theme.black,
borderRadius: theme.radius.md,
padding: `${theme.spacing.sm}px ${theme.spacing.lg}px`,
cursor: 'pointer',
margin: theme.spacing.md,
},
active: {
backgroundColor: theme.colors[theme.primaryColor][6],
color: theme.white,
},
}));
function Demo() {
const [active, setActive] = useState(0);
const { classes, cx } = useStyles();
return (
<div>
<button
className={cx(classes.button, { [classes.active]: active === 0 })}
onClick={() => setActive(0)}
type="button"
>
First
</button>
<button
className={cx(classes.button, { [classes.active]: active === 1 })}
onClick={() => setActive(1)}
type="button"
>
Second
</button>
</div>
);
}

Media queries

You can use nested media queries like in Sass. Within query body you can use theme.breakpoints defined with MantineProvider or just static values:

import { createStyles } from '@mantine/core';
const useStyles = createStyles((theme) => ({
container: {
height: 100,
backgroundColor: theme.colors.blue[6],
// Media query with value from theme
[`@media (max-width: ${theme.breakpoints.xl}px)`]: {
backgroundColor: theme.colors.pink[6],
},
// Static media query
'@media (max-width: 800px)': {
backgroundColor: theme.colors.orange[6],
},
},
}));
function Demo() {
const { classes } = useStyles();
return <div className={classes.container} />;
}

Keyframes

Keyframes demo
import { createStyles, keyframes } from '@mantine/core';
// Export animation to reuse it in other components
export const bounce = keyframes({
'from, 20%, 53%, 80%, to': { transform: 'translate3d(0, 0, 0)' },
'40%, 43%': { transform: 'translate3d(0, -30px, 0)' },
'70%': { transform: 'translate3d(0, -15px, 0)' },
'90%': { transform: 'translate3d(0, -4px, 0)' },
});
const useStyles = createStyles((theme) => ({
container: {
textAlign: 'center',
padding: theme.spacing.xl,
animation: `${bounce} 3s ease-in-out infinite`,
},
}));
function Demo() {
const { classes } = useStyles();
return <div className={classes.container}>Keyframes demo</div>;
}