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.

Features

  • As fast and lightweight as emotion: createStyles extends @emotion/react
  • Subscribes to your Mantine theming context
  • Supports all emotion features: automatic critical css extraction during server side rendering, lazy evaluation, dynamic theming, etc.
  • Server side rendering support: Next.js, Gatsby or any other environment
  • Fully featured TypeScript support

Basic usage

createStyles demo
import { createStyles } from '@mantine/core';
const useStyles = createStyles((theme, _params, getRef) => {
const child = getRef('child');
return {
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
[`& .${child}`]: {
fontSize: theme.fontSizes.xs,
},
},
},
child: {
// assign ref to element
ref: 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:

const useStyles = createStyles((theme, _params, getRef) => {
// create reference for future use
const button = getRef('button');
return {
button: {
// assign reference to selector
ref: 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 .${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 via 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>;
}

use-css hook

use-css hook is a simpler alternative to createStyles function. Hook returns css and cx functions. css function accepts styles object and returns class name. Note that css function cannot subscribe to theme, if you need this use useMantineTheme hook or createStyles function:

import { useCss, Button } from '@mantine/core';
function Demo({ active }) {
const { css, cx } = useCss();
return (
<Button
className={cx(css({ backgroundColor: 'red', opacity: 1 }), { [css({ opacity: 1 })]: active })}
>
Custom button
</Button>
);
}

Global styles

To set global styles use Global component:

import { Global } from '@mantine/core';
export function Demo() {
return (
<Global
styles={(theme) => ({
'*, *::before, *::after': {
boxSizing: 'border-box',
},
body: {
...theme.fn.fontStyles(),
backgroundColor: theme.colorScheme === 'dark' ? theme.colors.dark[7] : theme.white,
color: theme.colorScheme === 'dark' ? theme.colors.dark[0] : theme.black,
lineHeight: theme.lineHeight,
},
})}
/>
);
}

Inline styles

Most of Mantine components support Styles API. You can override default component styles inline or using MantineProvider the same way as with createStyles:

import { TabsProps, Tabs, Tab } from '@mantine/core';
import { ImageIcon, ChatBubbleIcon, GearIcon } from '@modulz/radix-icons';
function StyledTabs(props: TabsProps) {
return (
<Tabs
variant="unstyled"
styles={(theme) => ({
tabControl: {
backgroundColor: theme.colorScheme === 'dark' ? theme.colors.dark[6] : theme.white,
color: theme.colorScheme === 'dark' ? theme.colors.dark[0] : theme.colors.gray[9],
border: `1px solid ${theme.colorScheme === 'dark' ? theme.colors.dark[6] : theme.colors.gray[4]}`,
fontSize: theme.fontSizes.md,
padding: `${theme.spacing.lg}px ${theme.spacing.xl}px`,
'&:not(:first-of-type)': {
borderLeft: 0,
},
'&:first-of-type': {
borderTopLeftRadius: theme.radius.md,
borderBottomLeftRadius: theme.radius.md,
},
'&:last-of-type': {
borderTopRightRadius: theme.radius.md,
borderBottomRightRadius: theme.radius.md,
},
},
tabActive: {
backgroundColor: theme.colors.blue[7],
borderColor: theme.colors.blue[7],
color: theme.white,
},
})}
{...props}
/>
);
}
function Demo() {
return (
<StyledTabs>
<Tabs.Tab label="Settings" icon={<GearIcon width={16} height={16} />} />
<Tabs.Tab label="Messages" icon={<ChatBubbleIcon width={16} height={16} />} />
<Tabs.Tab label="Gallery" icon={<ImageIcon width={16} height={16} />} />
</StyledTabs>
);
}

Using createStyles without @mantine/core

You can use createStyles and MantineProvider without any other Mantine packages:

yarn add @mantine/styles
npm install @mantine/styles

After installation you can import createStyles and other function from @mantine/styles instead of @mantine/core and use it separately:

import { createStyles, MantineProvider, useMantineTheme } from '@mantine/styles';

Can I use other css-in-js libraries with Mantine?

Yes, you can. But please note that Mantine already uses emotion and you may have styles collisions and would have to overwrite styles with !important. Please consider choosing createStyle before picking other libraries.

Build fully functional accessible web applications faster than ever
Feedback
Your feedback is most valuable contribution to the project, please share how you use Mantine, what features are missing and what is done good
Leave feedback