はじめに
フォーム実装って、正直かなり面倒な作業なんですよね。
入力フィールドを並べて、バリデーションを書いて、エラーメッセージを表示して、送信処理を実装して...。同じようなコードを何度も書いている感覚、ありませんか。
React-Jsonschema-Form(以下RJSF)は、この問題を根本から解決してくれるライブラリです。GitHubで15,600スター以上、6,100以上のプロジェクトで採用されている実績があります。
個人的には、管理画面のフォーム実装でかなり助かっています。スキーマを定義するだけでフォームが生成されるって、最初は半信半疑だったんですけど、使ってみると「なんでもっと早く知らなかったんだ」という気持ちになりました。
React-Jsonschema-Formとは
RJSFは、JSON Schemaを使ってWebフォームを宣言的に構築できるReactコンポーネントです。
「データに関する事前知識がなく、JSON Schemaから直接フォームを生成したい場合」に最適なソリューション。要するに、スキーマさえあればフォームが自動で作れるという話です。
現在の最新バージョンはv6.2.1(2026年1月12日リリース)で、Apache 2.0ライセンスのオープンソースとして公開されています。393人以上のコントリビューターが開発に参加している、かなり活発なプロジェクトですね。
特徴・メリット
1. スキーマ駆動でフォーム生成
これ、RJSFの一番の特徴なんですけど、JSON Schemaを定義するだけでフォームが自動生成されます。
フィールドの型、必須項目、バリデーションルール...全部スキーマに書いておけば、あとはライブラリが勝手にやってくれる。コスパ的に、かなり効率が良いです。
2. 複数のUIフレームワークに対応
これも嬉しいポイント。10種類以上のテーマをサポートしています。
- Material UI v7
- Ant Design v5
- Chakra UI v3
- React-Bootstrap(Bootstrap v5)
- Semantic UI
- Daisy UI
- Mantine
既存のプロジェクトで使っているUIフレームワークがあれば、そのまま統合できる。デザインの一貫性を保ちながらフォーム実装ができるのは大きい。
3. バリデーションが標準装備
JSON Schemaのバリデーション仕様をそのまま使えます。ajv(Another JSON Schema Validator)がバックエンドで動いていて、リアルタイムバリデーションもエラーメッセージ表示も自動。
自分でバリデーションロジックを書く必要がほぼない。これだけで開発工数がかなり削減できます。
4. カスタマイズ性が高い
uiSchemaというプロパティで、見た目を細かく制御できます。フィールドの順序、ウィジェットの種類、ヘルプテキスト...スキーマとUIの設定を分離できるのが設計として良い。
5. TypeScriptサポート
型定義が充実しているので、TypeScriptで書くときのストレスがない。フォームデータの型推論もしっかり効きます。
インストール方法
前提条件
React 16以上がインストールされている必要があります。
基本パッケージのインストール
npm install @rjsf/core @rjsf/utils @rjsf/validator-ajv8
3つのパッケージが必要です:
@rjsf/core: コアコンポーネント@rjsf/utils: ユーティリティ関数@rjsf/validator-ajv8: バリデーター
UIテーマのインストール(オプション)
使いたいUIフレームワークに応じて追加インストールします。
# Material UI v7を使う場合
npm install @rjsf/mui @mui/material @mui/icons-material @emotion/react @emotion/styled
# Ant Design v5を使う場合
npm install @rjsf/antd antd
# Chakra UI v3を使う場合
npm install @rjsf/chakra-ui @chakra-ui/react
基本的な使い方
シンプルなフォーム
まずは最小構成から。
import Form from '@rjsf/core';
import validator from '@rjsf/validator-ajv8';
// JSON Schemaでフォームの構造を定義
const schema = {
title: "Todo",
type: "object",
required: ["title"],
properties: {
title: {
type: "string",
title: "タイトル"
},
done: {
type: "boolean",
title: "完了",
default: false
}
}
};
function App() {
const handleSubmit = ({ formData }) => {
console.log("送信データ:", formData);
};
return (
<Form
schema={schema}
validator={validator}
onSubmit={handleSubmit}
/>
);
}
これだけでテキスト入力とチェックボックスを持つフォームが生成されます。シンプル。
uiSchemaでカスタマイズ
見た目を調整したい場合はuiSchemaを使います。
const schema = {
type: "object",
properties: {
name: {
type: "string",
title: "名前"
},
bio: {
type: "string",
title: "自己紹介"
},
birthDate: {
type: "string",
title: "生年月日"
}
}
};
const uiSchema = {
bio: {
"ui:widget": "textarea", // テキストエリアに変更
"ui:options": {
rows: 5
}
},
birthDate: {
"ui:widget": "date" // 日付ピッカーに変更
}
};
function App() {
return (
<Form
schema={schema}
uiSchema={uiSchema}
validator={validator}
/>
);
}
Material UIテーマを使う
import Form from '@rjsf/mui';
import validator from '@rjsf/validator-ajv8';
import { ThemeProvider, createTheme } from '@mui/material/styles';
const theme = createTheme();
const schema = {
type: "object",
required: ["email", "password"],
properties: {
email: {
type: "string",
title: "メールアドレス",
format: "email"
},
password: {
type: "string",
title: "パスワード",
minLength: 8
}
}
};
const uiSchema = {
password: {
"ui:widget": "password"
}
};
function LoginForm() {
return (
<ThemeProvider theme={theme}>
<Form
schema={schema}
uiSchema={uiSchema}
validator={validator}
onSubmit={({ formData }) => console.log(formData)}
/>
</ThemeProvider>
);
}
見た目がMaterial UIスタイルになります。既存のMUIプロジェクトにスッと溶け込む。
バリデーションの活用
JSON Schemaのバリデーション機能をフル活用できます。
const schema = {
type: "object",
required: ["username", "email", "age"],
properties: {
username: {
type: "string",
title: "ユーザー名",
minLength: 3,
maxLength: 20,
pattern: "^[a-zA-Z0-9_]+$"
},
email: {
type: "string",
title: "メールアドレス",
format: "email"
},
age: {
type: "integer",
title: "年齢",
minimum: 18,
maximum: 120
},
website: {
type: "string",
title: "Webサイト",
format: "uri"
}
}
};
minLength、maxLength、pattern、format、minimum、maximum...これらのルールが自動でバリデーションに反映されます。
配列とネストしたオブジェクト
複雑なデータ構造も扱えます。
const schema = {
type: "object",
properties: {
name: {
type: "string",
title: "名前"
},
skills: {
type: "array",
title: "スキル",
items: {
type: "object",
properties: {
name: {
type: "string",
title: "スキル名"
},
level: {
type: "string",
title: "レベル",
enum: ["初級", "中級", "上級"]
}
}
}
},
address: {
type: "object",
title: "住所",
properties: {
prefecture: {
type: "string",
title: "都道府県"
},
city: {
type: "string",
title: "市区町村"
}
}
}
}
};
配列フィールドは追加・削除ボタン付きで自動生成されます。
実践的なユースケース
問い合わせフォーム
const contactSchema = {
type: "object",
required: ["name", "email", "message"],
properties: {
name: {
type: "string",
title: "お名前",
minLength: 1
},
email: {
type: "string",
title: "メールアドレス",
format: "email"
},
category: {
type: "string",
title: "お問い合わせ種別",
enum: ["製品について", "サービスについて", "その他"],
default: "製品について"
},
message: {
type: "string",
title: "お問い合わせ内容",
minLength: 10
}
}
};
const contactUiSchema = {
message: {
"ui:widget": "textarea",
"ui:options": {
rows: 6
}
}
};
ユーザー登録フォーム
const registrationSchema = {
type: "object",
required: ["username", "email", "password", "confirmPassword", "agree"],
properties: {
username: {
type: "string",
title: "ユーザー名",
minLength: 3,
maxLength: 20
},
email: {
type: "string",
title: "メールアドレス",
format: "email"
},
password: {
type: "string",
title: "パスワード",
minLength: 8
},
confirmPassword: {
type: "string",
title: "パスワード(確認)"
},
birthDate: {
type: "string",
title: "生年月日",
format: "date"
},
newsletter: {
type: "boolean",
title: "ニュースレターを受け取る",
default: false
},
agree: {
type: "boolean",
title: "利用規約に同意する",
const: true
}
}
};
const registrationUiSchema = {
password: {
"ui:widget": "password"
},
confirmPassword: {
"ui:widget": "password"
}
};
管理画面の設定フォーム
const settingsSchema = {
type: "object",
properties: {
general: {
type: "object",
title: "一般設定",
properties: {
siteName: {
type: "string",
title: "サイト名"
},
description: {
type: "string",
title: "サイト説明"
},
timezone: {
type: "string",
title: "タイムゾーン",
enum: ["Asia/Tokyo", "America/New_York", "Europe/London"],
enumNames: ["東京", "ニューヨーク", "ロンドン"]
}
}
},
notification: {
type: "object",
title: "通知設定",
properties: {
email: {
type: "boolean",
title: "メール通知",
default: true
},
push: {
type: "boolean",
title: "プッシュ通知",
default: false
},
frequency: {
type: "string",
title: "通知頻度",
enum: ["realtime", "daily", "weekly"],
enumNames: ["リアルタイム", "1日1回", "週1回"]
}
}
}
}
};
管理画面の設定項目って、増えがちなんですよね。スキーマで管理できると、追加・変更が楽になります。
カスタムウィジェット
標準ウィジェットで足りない場合は、自作もできます。
const RatingWidget = ({ value, onChange }) => {
return (
<div>
{[1, 2, 3, 4, 5].map((star) => (
<button
key={star}
type="button"
onClick={() => onChange(star)}
style={{ color: star <= value ? 'gold' : 'gray' }}
>
★
</button>
))}
</div>
);
};
const widgets = {
rating: RatingWidget
};
const schema = {
type: "object",
properties: {
satisfaction: {
type: "integer",
title: "満足度",
minimum: 1,
maximum: 5
}
}
};
const uiSchema = {
satisfaction: {
"ui:widget": "rating"
}
};
function App() {
return (
<Form
schema={schema}
uiSchema={uiSchema}
validator={validator}
widgets={widgets}
/>
);
}
まとめ
React-Jsonschema-Formを使って感じた変化:
- 開発速度: フォーム実装の時間が体感で半分以下に
- 保守性: スキーマベースなので変更に強い
- バリデーション: 自分で書く必要がほぼなくなった
- UIの一貫性: 既存のUIフレームワークとシームレスに統合
- 型安全性: TypeScriptとの相性が良い
正直なところ、管理画面のような入力項目が多い画面では、RJSFを使わない理由がないと思います。もちろん、細かいインタラクションが必要な顧客向けフォームでは、従来の実装が向いている場面もあります。
でも「スキーマを書けばフォームができる」という体験は、一度味わうと手放せなくなりますね。フォーム実装で消耗していた人は、ぜひ試してみてください。