mantine-form について
Mantine 9.x 向けに、`@mantine/form` でフォームを構築する方法を説明するスキルです。入力の連携、検証方法、制御モードと非制御モード、複雑なフォームのパターンを扱います。
主な機能
- 01非制御・制御フォームモード
- 02入力プロパティとフィールドの連携
- 03ルール、スキーマ、関数による検証
- 04送信、変更、フォーカス離脱時の検証
- 05値の監視と再レンダリングの動作
活用シーン
- 01Mantine の入力でフォームを構築
- 02スキーマによるフィールド検証
- 03入力中の再レンダリングの抑制
- 04条件付きまたは入れ子のフォームの作成
MCP 対応
付属のリファレンスで回答が見つからない場合、Mantine MCP サーバーのドキュメントを参照する方法を案内します。
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ mantinedev/ skills --skill mantine-formインストール後、Claude Code で/mantine-formを入力して読み込まれたか確認します。
同梱ファイルreferences/api.mdreferences/patterns.md
詳細
Mantine Form スキル
Mantine 9.x 向けに書かれています。
基本的なワークフロー
1. フォームを設定する
すべてのフォームで、非制御モードを使用することを推奨します。デフォルトは 'controlled' なので、明示的に設定してください。
const form = useForm({
mode: 'uncontrolled',
initialValues: {
email: '',
age: 0,
},
validate: {
email: isEmail('Invalid email'),
age: isInRange({ min: 18 }, 'Must be at least 18'),
},
});
2. getInputProps で入力を接続する
非制御モードでは、すべての入力に key={form.key('path')} が必要です。これがないと、form.setFieldValue、form.setValues、または form.reset の後に入力が更新されません。
<TextInput label="Email" key={form.key('email')} {...form.getInputProps('email')} />
<NumberInput label="Age" key={form.key('age')} {...form.getInputProps('age')} />
チェックボックスとスイッチには { type: 'checkbox' } が必要です。
<Checkbox
label="I agree"
key={form.key('agreed')}
{...form.getInputProps('agreed', { type: 'checkbox' })}
/>
Select、NumberInput、Radio.Group、Checkbox.Group など、value と onChange のペアを持つ Mantine の入力は、通常の getInputProps と key で動作します。
<Radio.Group label="Delivery" key={form.key('delivery')} {...form.getInputProps('delivery')}>
<Radio value="standard" label="Standard" />
<Radio value="express" label="Express" />
</Radio.Group>
Radio.Group を使わない単独のラジオボタンでは、form.getInputProps('color', { type: 'radio', value: 'red' }) を使用し、各ラジオボタンに key={form.key('color')} を追加してください。
error プロパティのないコンポーネント(Slider、RangeSlider、Rating、SegmentedControl、Chip.Group)では、{ withError: false } が必要です。エラーは自分で表示してください。
<Slider key={form.key('stock')} {...form.getInputProps('stock', { withError: false })} />
{form.errors.stock && <Text c="red" size="sm">{form.errors.stock}</Text>}
3. 送信を処理する
<form onSubmit={form.onSubmit((values) => console.log(values))}>
...
<Button type="submit">Submit</Button>
</form>
onSubmit は、バリデーションに合格した場合のみハンドラーを呼び出します。ハンドラーが Promise を返す場合、処理が完了するまで form.submitting は true になります。失敗を処理するには、次のようにします。
form.onSubmit(
(values, event) => save(values),
(errors, values, event) => console.log('Validation failed', errors) // { 'user.email': 'Invalid email' }
);
バリデーション
ルールオブジェクト(最も一般的)
validate: {
name: isNotEmpty('Required'),
email: isEmail('Invalid email'),
password: hasLength({ min: 8 }, 'Min 8 chars'),
confirmPassword: matchesField('password', 'Passwords do not match'),
}
スキーマ(zod、valibot、arktype などの Standard Schema ライブラリ)
import { z } from 'zod/v4';
import { schemaResolver, useForm } from '@mantine/form';
const schema = z.object({
email: z.email({ error: 'Invalid email' }),
age: z.number().min(18, { error: 'Must be at least 18' }),
});
const form = useForm({
mode: 'uncontrolled',
initialValues: { email: '', age: 0 },
validate: schemaResolver(schema, { sync: true }),
});
schemaResolver は組み込みなので、リゾルバーパッケージは必要ありません。同期スキーマでは { sync: true } を渡すと、form.validate() は Promise ではなく通常の結果を返します。
関数(フィールド間のロジック用)
validate: (values) => ({
endDate: values.endDate < values.startDate ? 'End must be after start' : null,
});
バリデーションを実行するタイミング
デフォルトでは、フィールドのバリデーションは送信時のみ実行されます。
validateInputOnChange: true, // also validate every field when it changes
validateInputOnChange: ['email'], // only the listed fields
validateInputOnBlur: ['email'], // same options, on blur
validateInputOnBlur: [`members.${FORM_INDEX}.email`], // list items, FORM_INDEX is exported from @mantine/form
フォーカスアウト時にバリデーションを実行すると、ユーザーが送信ボタンを押したときに表示されるエラーによってレイアウトがずれ、クリックがボタンに当たらないことがあります。エラーが表示されても動かない場所(たとえば固定位置のフッター)に送信ボタンを配置するか、変更時にバリデーションを実行してください。
モード
'uncontrolled'(推奨) | 'controlled'(デフォルト) | |
|---|---|---|
| 値の保存先 | Ref | React state |
form.values | 更新されません。form.getValues() を使用してください | 変更のたびに更新されます |
| 値の変更時の再レンダリング | なし | あり |
| 入力プロパティ | defaultValue + onChange | value + onChange |
入力に key={form.key(path)} を指定 | 必須 | 不要 |
非制御モードで再レンダリングされるもの
- 入力欄への入力では、フォームは再レンダリングされません。
- レンダリング中の
form.getValues()は、入力によって更新されません。値に基づいてフォームの一部を表示または非表示にするには、form.useWatchValue(path)を使用してください。ネストされたパスも使えます。例:form.useWatchValue('members.0.role')。 setFieldValue、setValues、insertListItem、removeListItem、reorderListItem、reset、initializeは再レンダリングを行うため、form.getValues().items.map(...)からリストをレンダリングしても問題ありません。form.errors、form.isDirty()、form.isDirty('path')、form.isTouched()、form.submitting、form.validatingは、どちらのモードでもレンダリング中に使用できます。これらが変化するとフォームは再レンダリングされます。
const shipsInternationally = form.useWatchValue('shipsInternationally');
リファレンス
基本的なフォームを超える内容については、コードを書く前に両方のリファレンスを読んでください。
references/patterns.md— 次の内容を確認する場合に読んでください:異なるレコードに同じフォームを再利用する(編集ダイアログ)、最初の無効なフィールドにフォーカスする、複数の送信ボタン、ユーザーの入力中に値を変更する、ネストされたオブジェクト、配列フィールド、リスト内のリストとformRootRule、非同期バリデーション(ルールと非同期スキーマ)、条件付きフィールド、条件付きバリデーション、複数ステップのフォーム、サーバーからの初期値の読み込み、保存と新しいベースラインの設定、コンポーネントの外部からのフォーム制御、カスタム入力、コンポーネント間でのフォームコンテキスト、transformValues、単独でのuseFieldの使用、送信後のサーバーエラーreferences/api.md— それ以外のすべてを確認する場合に読んでください。すべてのuseFormオプションと戻り値のメンバー(watch、onValuesChange、enhanceGetInputProps、resetField、clearFieldError、touchTriggerなど)に加え、useField、createFormContext、createFormActions、schemaResolver、組み込みバリデーター、型を一覧にしている唯一の場所です
情報の確認方法
リファレンスに必要な情報がない場合は、推測しないでください。
- Mantine MCP サーバー(
@mantine/mcp-server)が接続されている場合は、search_docsとget_item_docを使用してください - そうでない場合は、
https://mantine.dev/llms.txtを取得し、リンクされているフォームのページを開いてください