Custom components

This guide will help you learn how to integrate custom components with MantineProvider and how to add Styles API support.

Add Styles API support

You will need to use createStyles to add Styles API support to any component:

  1. Create useStyles hook that will be used in component with createStyles:
// MyComponent.styles.ts
import { createStyles, MantineNumberSize } from '@mantine/core';
// Styles params are optional
export interface MyComponentStylesParams {
radius?: MantineNumberSize;
}
export default createStyles((theme, { radius }: MyComponentStylesParams) => ({
// add all styles as usual
root: { borderRadius: theme.fn.radius(radius) },
title: { fontSize: theme.fontSizes.sm },
description: { fontSize: theme.fontSizes.xs },
}));
  1. Add styles to component with useStyles hook:
// MyComponent.tsx
import { DefaultProps, Selectors, MantineNumberSize, Box } from '@mantine/core';
import useStyles, { MyComponentStylesParams } from './MyComponent.styles.ts';
// This type will contain a union with all selectors defined in useStyles,
// in this case it will be `'root' | 'title' | 'description'`
type MyComponentStylesNames = Selectors<typeof useStyles>;
// DefaultProps adds system props support (margin, padding, sx, unstyled, styles and classNames).
// It accepts 2 types: styles names and styles params, both of them are optional
interface MyComponentProps extends DefaultProps<MyComponentStylesNames, MyComponentStylesParams> {
radius?: MantineNumberSize;
}
function MyComponent({
classNames,
styles,
unstyled,
radius,
className,
...others
}: MyComponentProps) {
const { classes, cx } = useStyles(
// First argument of useStyles is styles params
{ radius },
// Second argument is responsible for styles api integration
{ name: 'MyComponent', classNames, styles, unstyled }
);
// Use Box component as a base and spread ...others prop.
// By doing so, you will add sx, padding (pt, pb, px, etc.) and margin (my, m, mt, etc.) props support
return (
<Box className={cx(classes.root, className)} {...others}>
<div className={classes.title}>Awesome component</div>
<div className={classes.description}>With Styles API support</div>
</Box>
);
}

Done! Styles API support was added to MyComponent. You can now set classNames, styles and other system props:

import MyComponent from './MyComponent';
function Demo() {
return (
<>
<MyComponent classNames={{ title: 'title-class', root: 'root-class' }} />
<MyComponent sx={{ backgroundColor: 'orange' }} />
<MyComponent
styles={(theme) => ({
title: { color: theme.colors.gray[5] },
description: { fontSize: 14 },
})}
/>
</>
);
}

You can also add styles and classNames on MantineProvider:

import { MantineProvider } from '@mantine/core';
function Demo() {
return (
<MantineProvider
theme={{
components: {
// Use component name that you've defined in useStyles({}, { name: 'MyComponent' })
MyComponent: {
classNames: { title: 'title-class', root: 'root-class' },
styles: (theme) => ({
title: { color: theme.colors.gray[5] },
description: { fontSize: 14 },
}),
},
},
}}
>
<App />
</MantineProvider>
);
}

Add default props support

You can add default props support to any component with useComponentDefaultProps hook:

import { useComponentDefaultProps } from '@mantine/core';
interface CustomComponentProps {
radius?: number;
children: React.ReactNode;
}
const defaultProps: Partial<CustomComponentProps> = {
radius: 6,
};
function CustomComponent(props: CustomComponentProps) {
const { radius, children } = useComponentDefaultProps('CustomComponent', defaultProps, props);
return <div style={{ borderRadius: radius }}>{children}</div>;
}

Then you will be able to add default props on MantineProvider:

import { MantineProvider } from '@mantine/core';
function Demo() {
return (
<MantineProvider
theme={{
components: {
// Use component name that you've provided
// in the first argument of useComponentDefaultProps
CustomComponent: {
defaultProps: { radius: 12 },
},
},
}}
>
<App />
</MantineProvider>
);
}

DefaultProps type

DefaultProps adds system props support (margin, padding, sx, unstyled, styles and classNames). It accepts 2 types: styles names and styles params, both of them are optional. When you build components there might be 4 cases:

import { DefaultProps } from '@mantine/core';
type StylesNames = 'root' | 'title';
type StylesParams = { radius: number };
// Case 1: component has styles params and styles names
interface Props extends DefaultProps<StylesNames, StylesParams> {}
// Case 2: component has only styles names
interface Props extends DefaultProps<StylesNames> {}
// Case 3: component has only styles params
interface Props extends DefaultProps<never, StylesParams> {}
// Case 4: component does not have styles params and styles names
interface Props extends DefaultProps {}