mantine-custom-components について
Mantine 9.xでカスタムコンポーネントを作る開発者向けのスキルです。コンポーネント構造、スタイル、バリアント、テーマ連携を扱い、適切なファクトリーパターンの選択も説明します。
主な機能
- 01Mantine 9.xのコンポーネントテンプレート
- 02Styles APIのプロパティとクラス
- 03バリアント、サイズ、CSS変数
- 04テーマの色とサイズのヘルパー
- 05ファクトリーパターンと型
- 06テーマ拡張とプロパティのプリセット
活用シーン
- 01カスタムMantineコンポーネントの作成
- 02バリアントとサイズスタイルの追加
- 03コンポーネントの既定値のテーマ連携
- 04ポリモーフィックまたはジェネリックなプロパティ向けファクトリー選択
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ mantinedev/ skills --skill mantine-custom-componentsインストール後、Claude Code で/mantine-custom-componentsを入力して読み込まれたか確認します。
同梱ファイルreferences/api.mdreferences/patterns.md
詳細
Mantine カスタムコンポーネントのスキル
Mantine 9.x 向けに作成されています。
コンポーネントのテンプレート
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));
}
React 19 では ref は通常のプロップです。props に渡され、...others を通じてルート要素に届きます。
追加のコードなしで利用できるもの:
getStyles('selector')でレンダリングされるすべての要素に、静的クラスmantine-MyComponent-selectorが付与されます。classNames、styles、vars、attributesプロップと、テーマ内のMyComponent.extend()における同じキー。unstyledは CSS モジュールのクラスを削除します。静的クラスとルートの CSS 変数は残ります。MyComponent.extend()とMyComponent.withProps()の静的関数。withPropsは実行時にプロップをプリセットしますが、型は変更しません。必須プロップは TypeScript では引き続き必須となるため、プリセットするプロップは任意にしてください。
バリアントとサイズ
variant と size を Box に渡すと、CSS でスタイルを指定するための data-variant 属性と data-size 属性が設定されます。
variant を getStyles に渡すと、CSS モジュールに定義されている場合は root--{variant} クラスも適用されます。
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; }
}
1 つの size プロップでサイズを指定する場合:トークン値を CSS で定義し、getSize で選択します。size に渡された数値または任意の CSS 値はそのまま使用されます(getSize(60, 'x') は 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));
}
テーマに連動する色は、vars リゾルバーで theme.variantColorResolver({ color: color || theme.primaryColor, theme, variant: variant || 'filled', autoContrast }) を使って解決します。これは background、hover、color を色として、border を完全な border の省略記法の値(1px solid transparent)として返します。filled、light、outline、subtle、transparent、white、default の各バリアントに対応しています。autoContrast: undefined の場合は theme.autoContrast が使われます。単一の色には getThemeColor(color, theme) を使います。'blue'、'teal.7'、CSS の色を受け付けます。
.root {
background-color: var(--my-bg);
color: var(--my-color);
border: var(--my-bd); /* the whole shorthand, not border-color */
}
リゾルバーはテーマから取得されるため、アプリではコンポーネントに手を加えることなく、独自のバリアント(variant="danger")を追加したり、既存のバリアントの色を変更したりできます。プロップのインターフェースで variant を再宣言しないでください。StylesApiProps ですでに、独自のバリアントと任意の文字列が型付けされています。
Factory のバリアント — どれを使うか
| シナリオ | Factory 関数 | 型 |
|---|---|---|
| 標準コンポーネント | factory() | Factory<{}> |
component プロップに対応(ポリモーフィック) | polymorphicFactory() | PolymorphicFactory<{}> — defaultComponent と defaultRef を追加 |
ジェネリックに応じてプロップが変化する(例:multiple) | genericFactory() | Factory<{ signature: ... }> |
polymorphicFactory は必要な場合に限って使用してください。TypeScript の負荷が増え、IDE のオートコンプリートが遅くなります。
すべての Factory コンポーネントは、component の代わりに renderRoot={(props) => <a {...props} />} も受け付けます。
Factory の型フィールド
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
}>
テーマとの統合
ユーザーとテーマは、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) } }),
}),
},
});
theme.components では、サブコンポーネントはドットを付けずに登録します。MyCardSection: MyCard.Section.extend({ defaultProps }) のようにします。
参考資料
コードを書く前に、作業内容に該当する箇所を読んでください。
references/patterns.md— 完全な実例が記載されています。サブコンポーネント(Card.Section)を持つコンポーネントについては「Compound component with context」、既存の Mantine の入力コンポーネントやコンポーネントを内部でレンダリングし、classNames/stylesを転送する必要があるコンポーネントについては「Wrapping a Mantine component」、共通のベースを持つコンポーネント群については「Components that share theme configuration」、インラインスタイルを持つforwardRefコンポーネントを移行する場合は「Converting an existing component」、componentプロパティについては「Polymorphic component」、型パラメーターに依存するプロパティについては「Generic component」、extendとwithPropsについては「Theme integration」を読んでください。references/api.md— 上記のテンプレート以外のコンポーネントでは、このファイルを読んでください。getStylesのオプション(focusable)、modプロパティ、テーマヘルパーの戻り値、MantineThemeProviderとテーマ関数が受け取る値について記載されているのはここだけです。すべての関数と型を確認してください。factoryのバリエーション、useProps、useStylesとgetStylesのオプション、createVarsResolver、createSafeContext、StylesApiProps、CompoundStylesApiProps、BoxProps(modを含む)、ElementProps、テーマヘルパー(getSize、getRadius、getThemeColorなど)が含まれます。
調べ方
参考資料に必要な情報がない場合は、推測しないでください。
- Mantine MCP サーバー(
@mantine/mcp-server)が接続されている場合は、search_docs、get_item_doc、get_apiを使用してください。 - それ以外の場合は、
https://mantine.dev/llms.txtを取得し、Styles API、variants and sizes、custom components の各ページを開いてください。