これは「react-jsonschema-formのカレンダー | Advent Calendar 2023 - Qiita」の6日目の記事です。
この記事では、react-jsonschema-form (RJSF) にて、どのようにフォームを表示するかを uiSchema
で定義してみます。
目次
- 環境
- uiSchemaとは
- uiSchemaの ui:XXX と ui:options:XXX という書き方の違いについて
- string型の項目に uiSchema の定義を割り当てる
- ui:emptyValueの挙動を確認する
- array型の項目に uiSchema の定義を割り当てる
- buttonに uiSchema の定義を割り当てる
- ソースコード
環境
- react-jsonschema-form 5.15.0
- React 18.2.0
- React Router 6.20.1
なお、テーマは MUI v5 を使っています。他のテーマの場合、見え方が異なるかもしれません。
また、今回は以下のようなコンポーネントを定義し、
- JSON Schema
- uiSchema
の部分を差し替える感じの実装となっています。
そのため、記事中のソースコードでは JSON Schema や uiSchema 以外の部分は省略しています。
import {RJSFSchema, UiSchema} from "@rjsf/utils"; import Form from "@rjsf/mui"; // MUI version import validator from "@rjsf/validator-ajv8"; export const UiSchemaOption = () => { const schema: RJSFSchema = { // JSON Schemaの定義を追加する場所 } const uiSchema: UiSchema = { // uiSchemaの定義を追加する場所 } // onSubmitの引数の説明は以下 // https://rjsf-team.github.io/react-jsonschema-form/docs/api-reference/form-props#onsubmit const onSubmit = ({formData}, _event) => { console.log(formData) } return ( <div style={{width: '400px'}}> <Form schema={schema} uiSchema={uiSchema} validator={validator} onSubmit={onSubmit} /> </div> ) }
uiSchemaとは
RJSFでは JSON Schema
を使って、何の入力項目が存在するかを定義します。
一方、RJSFの uiSchema
を使うことで、入力項目をどのように表示するかを定義します。
ただ、実際にJSON SchemaとuiSchemaを使って実装してみたほうが分かりやすいことから、以降ではRJSFの公式ドキュメントを見ながら色々な定義を試してみます。
uiSchemaの ui:XXX と ui:options:XXX という書き方の違いについて
uiSchemaでは
- ui:XXX
- ui:options:XXX
という2通りの書き方があります。
これらの違いについては、RJSFの公式ドキュメントに記載がありました。
uiSchema | react-jsonschema-form
公式ドキュメントによると、
- 定義の書き方は異なるものの、結果は同じ
ui:options
の中にui:options
をネストできない
と分かりました。
では、実際に試してみます。
stringInput
と stringInput2
という2つのstring型の項目をJSON Schemaへ用意し、それぞれの定義で差が出るかを確認します。
export const UiSchemaOption = () => { const schema: RJSFSchema = { title: "uiSchema option", type: "object", required: [], properties: { stringInput: { type: "string", }, stringInput2: { type: "string" } } } const uiSchema: UiSchema = { stringInput: { "ui:options": { widget: "textarea", rows: 10, }, }, stringInput2: { "ui:widget": "textarea", "ui:rows": 10 }, } // 略 }
動かしてみたところ、両方とも同じ結果になりました。
ちなみに、その他の違いとして、 ui:options
の場合はIDEの補完もききました。
string型の項目に uiSchema の定義を割り当てる
uiSchema
で定義できるものについては、公式ドキュメントの以下のページにあります。
ui:XXX or ui:options.XXX | uiSchema | react-jsonschema-form
ここでは、string型の項目を用意し、そこにuiSchemaを適用したときの様子を確認します。
まず、JSON Schemaで stringInput
という項目を用意します。
const schema: RJSFSchema = { title: "uiSchema for string", type: "object", required: [], properties: { stringInput: { type: "string", } } }
次に uiSchemaで stringInput
に対する定義を用意します。
オブジェクトのキーとして stringInput
を用意し、その値として uiSchema の内容を書いていきます。
今回は
- help
- description
- placeholder
- title
を定義するとどのように表示されるか見てみます。
const uiSchema: UiSchema = { stringInput: { "ui:options": { help: "my help text", description: "my description", placeholder: "my placeholder", title: "my title" }, } }
上記定義の場合、以下のような表示となりました。
ui:emptyValueの挙動を確認する
uiSchemaの定義を色々試している中で、 ui:emptyValue
の挙動が気になったことから、ここに残しておこうと思います。
https://rjsf-team.github.io/react-jsonschema-form/docs/api-reference/uiSchema/#emptyvalue
例えば、以下のようなJSON SchemaとuiSchemaがあったとします。
const schema: RJSFSchema = { title: "uiSchema for emptyValue", type: "object", required: [], properties: { stringWithEmptyValue: { type: "string", } } } const uiSchema: UiSchema = { stringWithEmptyValue: { "ui:options": { emptyValue: "empty" }, } }
この定義を使うと、以下のように表示されます。
このまま何も入力せずにsubmitボタンをクリックした場合、consoleには {}
というオブジェクトが表示されます。
続いて、 aaa
などを入力した後その文字列を削除します。
すると、以下のような表示になり、 emptyValue
で定義した値(ここでは empty
)が表示されます。
この状態でsubmitすると、consoleには {stringWithEmptyValue: 'empty'}
が表示されます。
また、JSON Schemaに default
がある時に uiSchema に emptyValue
を定義した時の表示も見てみます。
const schema: RJSFSchema = { title: "uiSchema for emptyValue", type: "object", required: [], properties: { stringWithEmptyValueAndDefault: { type: "string", default: "foo" } } } const uiSchema: UiSchema = { stringWithEmptyValueAndDefault: { "ui:options": { emptyValue: "empty" } } }
すると default
で定義した値が表示されました。
なお、 default
で定義した値をすべて削除すると、先ほどと同様 emptyValue
の値が表示されました。
array型の項目に uiSchema の定義を割り当てる
RJSFのデータ型には array
も存在します。
array
の uiSchema については独自の定義も存在します。
Array item uiSchema options | Arrays | react-jsonschema-form
そこで、array型を使う時の定義方法を見ていきます。
例えば、「stringInput
と numberInput
を持つobject型」を要素に持つarray型のJSON Schemaがあるとします。
const schema: RJSFSchema = { title: "uiSchema for array", type: "array", items: { type: "object", properties: { stringInput: { type: "string" }, numberInput: { type: "number" } } } }
この場合、uiSchemaは
- array型自体の uiSchema は、トップレベルのキーとして定義
- array型の要素の uiSchema は、
items
キーの中にproperties
のキーを定義
という形で定義します。
例えば、
- arrayにはコピーボタンを表示
- arrayの場合、デフォルトではコピーボタンは非表示
- arrayの要素の
stringInput
項目には help を表示
としたい場合は以下の定義となります。
const uiSchema: UiSchema = { "ui:copyable": true, items: { stringInput: { "ui:help": "my array help" } } }
実際に表示してみると、想定どおりとなりました。
buttonに uiSchema の定義を割り当てる
uiSchemaでは、RJSFでデフォルト表示するsubmitボタンの表示形式も定義できます。
submitButtonOptions | uiSchema | react-jsonschema-form
例えば、
- submitボタンのテキストを
my submit
にする - submitボタンのHTMLのclass属性に
MY_CLASS
を追加する
としたい場合のuiSchemaは以下です。
const uiSchema: UiSchema = { "ui:submitButtonOptions": { submitText: "my submit", // classNameはpropsの中しか反映されない className: "MY_CLASS_FOO", props: { // submitTextはpropsの中に書くとwarningが出て、描画されない // submitText: "my submit", className: "MY_CLASS" }, } }
なお、コメントとして記載していますが、
className
はprops
の中でしか反映されないsubmitText
はprops
の中に書くとwarningが出て描画されない
ようです。
ちなみに、submitTextのwarningは以下でした。
react-dom.development.js:86 Warning: React does not recognize the
submitText
prop on a DOM element. If you intentionally want it to appear in the DOM as a custom attribute, spell it as lowercasesubmittext
instead. If you accidentally passed it from a parent component, remove it from the DOM element.
そして、このuiSchemaの定義で表示してみると、buttonのテキストが変更され、class属性にも定義した値が追加されていました。
ソースコード
Githubにあげました。
https://github.com/thinkAmi-sandbox/rjsf_advent_calendar_2023
今回のプルリクはこちら。
https://github.com/thinkAmi-sandbox/rjsf_advent_calendar_2023/pull/5