react-jsonschema-formで、additionalPropertiesを使った時の表示を確認してみる

これは「react-jsonschema-formのカレンダー | Advent Calendar 2023 - Qiita」の21日目の記事です。

JSON Schemaには additionalProperties キーワードがあります。
Additional Properties | JSON Schema - object

これを使うことで、JSON Schemaにて定義していないプロパティをJSONに含めることができるか制御します。

 
さて、この additionalProperties ですが、 react-jsonschema-form (RJSF) でも使えます。
Additional properties | Objects | react-jsonschema-form

そこで、RJSFで使った場合にどのように表示されるかを確認してみます。

 
目次

 

環境

  • react-jsonschema-form 5.15.0
  • React 18.2.0
  • React Router 6.20.1

 

additionalPropertiesに色々な定義をしてみる

additionalProperties に対して、色々定義してその表示を確認してみます。

 

string型の項目を定義した時の挙動

挙動確認

まずは、additionalPropertiesにstring型の項目を追加して、どのように表示されるか確認してみます。

JSON Schema的にはこんな感じです。

なお、additionalPropertiesでも

  • title
  • description
  • default

の各値を定義できるため、ここでも定義して表示を確認してみます。

const schema: RJSFSchema = {
  title: "Additional String",
  type: "object",
  properties: {
    mainInput: {
      type: "string"
    }
  },
  additionalProperties: {
    type: "string",
    title: "my title",
    description: "my description",
    default: "Default",
  }
}

 
コンポーネントの全体像はこちら。

import {RJSFSchema} from "@rjsf/utils";
import Form from "@rjsf/mui";
import validator from "@rjsf/validator-ajv8";

export const AdditionalStringForm = () => {
  const schema: RJSFSchema = { ... } // JSON Schemaは省略

  // 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}
        validator={validator}
        onSubmit={onSubmit}
      />
    </div>
  )
}

 
次に表示してみます。初期表示は以下のようになりました。

 
mainInputの右下あたりにある + ボタンをクリックすると、 additionalProperties で定義したstring型の入力項目が表示されました。

  • title
  • description

が表示されています。

 
もう一度 + をクリックすると、もう一つ入力項目が増えました。

 
この状態でsubmitボタンをクリックすると、additionalPropertiesで設定したキーと値が送信されました。

 

defaultで定義した値が表示されないというissueあり

先ほど見た通り、titleやdescriptionの各値が表示される一方で、defaultの値は表示されませんでした。

これについては以下にissueがあり、機能としては存在しないようでした。
Set default values for additionalProperties · Issue #3915 · rjsf-team/react-jsonschema-form

 

defaultの定義方法によっては、挙動がおかしくなるというissueあり

JSON Schemaのルート階層に default キーワードを指定した場合、挙動がおかしくなるというissueがありました。
Object defaults for "additionalProperties" result in rows that cannot be deleted and have side effects when modified · Issue #3759 · rjsf-team/react-jsonschema-form

 
もしルート階層に default を定義したい場合は気をつけたほうが良さそうです。

 

object型の項目を定義した時の挙動

次に additionalProperties に object型の項目を定義してみます。

 

単一のプロパティを持つobject型の場合

まずは単一のプロパティの表示を確認します。

用意したJSON Schemaはこんな感じです。

なお、他の部分はstring型のときと同じなため、省略します。

const schema: RJSFSchema = {
  title: "Additional Object Only String",
  type: "object",
  properties: {
    mainInput: {
      type: "string"
    }
  },
  additionalProperties: {
    type: "object",
    properties: {
      additionalString: {
        type: "string",
        title: "additional title",
        description: "additional description",
        default: "string default"
      }
    }
  }
}

 
この状態で表示し、 + ボタンをクリックすると以下の表示となりました。

string型と異なり、titleとdescriptionに加え、defaultで指定した値も表示されています。

 
もう一度 + ボタンをクリックした後submitしたところ、additionalPropertiesの値は送信されていました。

 

複数のプロパティを持つobject型の場合

続いて、複数のプロパティを持つobject型の表示を確認してみます。

JSON Schemaはこちら。

const schema: RJSFSchema = {
  title: "Additional Object",
  type: "object",
  properties: {
    mainInput: {
      type: "string"
    }
  },
  additionalProperties: {
    type: "object",
    title: "my title",
    description: "my description",
    default: "Default",
    properties: {
      additionalString: {
        type: "string",
        title: "string title",
        description: "string description",
        default: "string default"
      },
      additionalInteger: {
        type: "integer",
        title: "integer title",
        description: "integer description",
        default: 10
      }
    }
  }
}

 
+ ボタンを押してadditionalPropertiesを表示したところ、以下となりました。

 
こちらも + ボタンをもう一度クリックしてsubmitしたところ、各項目のデータが送信されました。

 

JSON Schemaがサポートしていない型を定義した時の挙動

RJSFでは、JSON Schemaがサポートしていない時に表示するテンプレートなどが定義されています。

 
では、JSON Schemaがサポートしていない型をadditionalPropertiesで定義したときにどのような表示となるかを確認してみます。

用意したJSON Schemaは以下です。

なお、以下の定義を使う場合は型エラーが発生した状態となります。

const schema: RJSFSchema = {
  title: "Additional Unsupported Type",
  type: "object",
  properties: {
    mainInput: {
      type: "string"
    }
  },
  additionalProperties: {
    type: "unsupported"
  }
}

 
初期表示後 + ボタンを押すと、以下の表示となりました。

 
また、この状態でsubmitするとバリデーションエラーとなり、以下のメッセージが表示されました。

schema is invalid: data/additionalProperties/type must be equal to one of the allowed values, data/additionalProperties/type must be array, data/additionalProperties/type must match a schema in anyOf, data/properties/newKey/type must be equal to one of the allowed values, data/properties/newKey/type must be array, data/properties/newKey/type must match a schema in anyOf

 

uiSchemaでhidden定義をした時の挙動

RJFSでは、uiSchemaで hidden widgetを定義することで、定義した項目をhiddenにできます。
Hidden widgets | Widgets | react-jsonschema-form

そこで、additionalPropertiesの項目をhiddenにした場合にどのような表示になるかためしてみます。

まずはJSON Schemaを定義します。

今回は hiddenString をhidden項目とします。

また、title・description・defaultも定義し、それらの項目がどう表示されるかを確認します。

const schema: RJSFSchema = {
  title: "Additional Hidden",
  type: "object",
  properties: {
    mainInput: {
      type: "string"
    }
  },
  additionalProperties: {
    type: "object",
    title: "my title",
    description: "my description",
    default: "Default",
    properties: {
      hiddenString: {
        type: "string",
        title: "string title",
        description: "string description",
        default: "string default"
      }
    }
  }
}

 
続いて、uiSchemaにhidden項目の定義を行います。

なお、公式ドキュメントに

You can also define uiSchema options for additionalProperties by setting the additionalProperties attribute in the uiSchema.

https://rjsf-team.github.io/react-jsonschema-form/docs/json-schema/objects/#additional-properties

とあるように、 additionalProperties プロパティの下に、hiddenとしたい項目のキーを指定します。

const uiSchema: UiSchema = {
  additionalProperties: {
    hiddenString: {
      'ui:widget': 'hidden'
    }
  }
}

 
あとはFormのpropsに schemauiSchema を渡します。

<Form
  schema={schema}
  uiSchema={uiSchema}
  validator={validator}
  onSubmit={onSubmit}
/>

 
では実際に表示してみます。

+ ボタンをクリックすると、titleとdescriptionだけが表示されました。

 
さらに + ボタンをクリックすると、もう1セット、titleとdescriptionが表示されました。

 
この状態でsubmitすると、hiddenのdefault値が送信されました。

 

ソースコード

Githubにあげました。
https://github.com/thinkAmi-sandbox/rjsf_advent_calendar_2023

今回のプルリクはこちら。
https://github.com/thinkAmi-sandbox/rjsf_advent_calendar_2023/pull/19