mantine-custom-components
Skill63 starsChanged 40 days agoMITView on GitHub
Build custom components that integrate with Mantine's theming, Styles API, and core features. Use this skill when: (1) creating a new component using factory(), polymorphicFactory(), or genericFactory(), (2) adding Styles API support (classNames, styles, vars, unstyled), (3) implementing CSS variables via createVarsResolver, (4) building compound components with sub-components and shared context, (5) registering a component with MantineProvider via Component.extend(), or (6) any task involving Factory, useProps, useStyles, BoxProps, StylesApiProps, or ElementProps in @mantine/core.
1 other project uses a version of this.
Adopted by
Most recently taken up by
- RostislavDugin/postgresusword for word, first seen Nov 8, 2026
Other versions1 project uses a version of this.
Word for word · 1
- RostislavDugin/postgresus★ 9.3k100% same
Edited · 0
None found.
Wrote their own version · 0
None found.
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository2 other files it gives its agents.
- mantine-comboboxSkill
- mantine-formSkill
The file
We split this skill into the rules it gives an agent
6 rules. About 0 are common, 2 are distinctive, and 4 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈2
Distinctive · estimate
This author's own choices. Worth a look.
4
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 79
Every element rendered with getStyles('selector') gets the static class mantine-MyComponent-selector.
- Very specific: line 148
Use polymorphicFactory sparingly — it adds TypeScript overhead and slows IDE autocomplete.
- Very specific: line 149
Every factory component also accepts renderRoot={(props) => <a {...props} />} as an alternative to component.
- Distinctive: line 190
Read the part that matches the task before writing code:
- Distinctive: line 197
If the references do not cover what you need, do not guess:
- Very specific: line 199
If the Mantine MCP server (@mantine/mcp-server) is connected, use search_docs, get_item_doc and get_api
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Mantine Custom Components Skill
Written for Mantine 9.x.
Component template
import {
Box, BoxProps, createVarsResolver, ElementProps,
factory, Factory, getRadius, MantineRadius,
StylesApiProps, useProps, useStyles,
} from '@mantine/core';
import classes from './MyComponent.module.css';
export type MyComponentStylesNames = 'root' | 'inner';
export type MyComponentVariant = 'filled' | 'outline';
export type MyComponentCssVariables = { root: '--my-radius' };
export interface MyComponentProps
extends BoxProps, StylesApiProps<MyComponentFactory>, ElementProps<'div'> {
radius?: MantineRadius;
}
export type MyComponentFactory = Factory<{
props: MyComponentProps;
ref: HTMLDivElement;
stylesNames: MyComponentStylesNames;
vars: MyComponentCssVariables;
variant: MyComponentVariant;
}>;
const defaultProps = {} satisfies Partial<MyComponentProps>;
const varsResolver = createVarsResolver<MyComponentFactory>((_theme, { radius }) => ({
// undefined leaves the variable unset, so the CSS fallback (theme default radius) applies
root: { '--my-radius': radius === undefined ? undefined : getRadius(radius) },
}));
export const MyComponent = factory<MyComponentFactory>((_props) => {
const props = useProps('MyComponent', defaultProps, _props);
const { classNames, className, style, styles, unstyled, vars, attributes, radius, ...others } = props;
const getStyles = useStyles<MyComponentFactory>({
name: 'MyComponent', classes, props,
className, style, classNames, styles, unstyled, vars, attributes, varsResolver,
});
return <Box {...getStyles('root')} {...others} />;
});
MyComponent.displayName = 'MyComponent';
MyComponent.classes = classes;
MyComponent.varsResolver = varsResolver;/* MyComponent.module.css */
.root {
border-radius: var(--my-radius, var(--mantine-radius-default));
}ref is a regular prop in React 19: it arrives in props and reaches the root element through ...others.
What you get without extra code:
- Every element rendered with
getStyles('selector')gets the static classmantine-MyComponent-selector. classNames,styles,varsandattributesprops, and the same keys inMyComponent.extend()in the theme.unstyledremoves the CSS module classes. Static classes and the CSS variables on the root stay.MyComponent.extend()andMyComponent.withProps()static functions.withPropspresets props at runtime but does not change types: a required prop stays required for TypeScript, so make props you intend to preset optional.
Variants and sizes
Pass variant and size to Box: it sets data-variant and data-size attributes to style in CSS.
Passing variant to getStyles additionally applies the root--{variant} class when the CSS module defines one:
const { variant, size, ...others } = props;
<Box variant={variant} size={size} {...getStyles('root', { variant })} {...others} />.root {
&[data-variant='outline'] { border: 1px solid var(--my-color); }
&[data-size='lg'] { height: 50px; }
}Sizes driven by one size prop: define the token values in CSS and select one with getSize. A
number or any CSS value passed as size is used as is (getSize(60, 'x') returns calc(3.75rem * var(--mantine-scale))).
root: { '--card-padding': getSize(size, 'card-padding'), '--card-fz': getFontSize(size) },.root {
--card-padding-sm: 12px;
--card-padding-md: 16px;
--card-padding-lg: 24px;
padding: var(--card-padding, var(--card-padding-md));
}For colors that follow the theme, resolve them in the vars resolver with
theme.variantColorResolver({ color: color || theme.primaryColor, theme, variant: variant || 'filled', autoContrast })
— it returns background, hover and color as colors and border as a full border shorthand value
(1px solid transparent). It knows the variants filled, light, outline, subtle, transparent, white and
default; autoContrast: undefined falls back to theme.autoContrast. For a single color use
getThemeColor(color, theme): it accepts 'blue', 'teal.7' and CSS colors.
.root {
background-color: var(--my-bg);
color: var(--my-color);
border: var(--my-bd); /* the whole shorthand, not border-color */
}Because the resolver comes from the theme, an app can add its own variant (variant="danger") or
recolor an existing one without touching the component. Do not redeclare variant in your props
interface: StylesApiProps already types it as your variants plus any string.
Factory variant — which to use
| Scenario | Factory function | Type |
| Standard component | factory() | Factory<{}> |
Supports component prop (polymorphic) | polymorphicFactory() | PolymorphicFactory<{}> — add defaultComponent and defaultRef |
Props change based on a generic (e.g. multiple) | genericFactory() | Factory<{ signature: ... }> |
Use polymorphicFactory sparingly — it adds TypeScript overhead and slows IDE autocomplete.
Every factory component also accepts renderRoot={(props) => <a {...props} />} as an alternative to component.
Factory type fields
Factory<{
props: MyComponentProps; // required
ref: HTMLDivElement; // element type for the forwarded ref
stylesNames: 'root' | 'inner'; // union of Styles API selectors
vars: { root: '--my-var' }; // CSS variable map per selector
variant: 'filled' | 'outline'; // accepted variant strings
staticComponents: { // sub-components (compound pattern)
Item: typeof MyComponentItem;
};
compound: true; // only for sub-components; disables theme classNames/styles/vars
ctx: { stepsCount: number }; // only if needed; passed to classNames/styles/vars functions as third arg
signature?: (...) => JSX.Element; // only for genericFactory
}>Theme integration
Users and the theme can override defaults via Component.extend():
const theme = createTheme({
components: {
MyComponent: MyComponent.extend({
defaultProps: { radius: 'xl' },
classNames: { root: 'my-root' },
styles: { root: { color: 'red' } },
vars: (_theme, props) => ({ root: { '--my-radius': getRadius(props.radius) } }),
}),
},
});In theme.components, sub-components are registered without the dot: MyCardSection: MyCard.Section.extend({ defaultProps }).
References
Read the part that matches the task before writing code:
references/patterns.md— complete examples. Read "Compound component with context" for components with sub-components (Card.Section), "Wrapping a Mantine component" when the component renders an existing Mantine input or component inside and must forwardclassNames/stylesto it, "Components that share theme configuration" for a family of components with a common base, "Converting an existing component" when migrating aforwardRefcomponent with inline styles, "Polymorphic component" for acomponentprop, "Generic component" for props that depend on a type parameter, "Theme integration" forextendandwithPropsreferences/api.md— read it for any component beyond the template above: it is the only place that documentsgetStylesoptions (focusable), themodprop, theme helper outputs,MantineThemeProviderand what theme functions receive. Every function and type:factoryvariants,useProps,useStylesandgetStylesoptions,createVarsResolver,createSafeContext,StylesApiProps,CompoundStylesApiProps,BoxProps(includingmod),ElementProps, theme helpers (getSize,getRadius,getThemeColor...)
Looking things up
If the references do not cover what you need, do not guess:
- If the Mantine MCP server (
@mantine/mcp-server) is connected, usesearch_docs,get_item_docandget_api - Otherwise fetch
https://mantine.dev/llms.txtand open the Styles API, variants and sizes, and custom components pages
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

