Juniper/react-jsonschema-form

Name: react-jsonschema-form

Owner: Juniper Networks

Description: A React component for building Web forms from JSON Schema.

Forked from: mozilla-services/react-jsonschema-form

Created: 2018-02-01 14:15:35.0

Updated: 2018-02-01 14:15:38.0

Pushed: 2018-02-01 16:22:38.0

Homepage: https://mozilla-services.github.io/react-jsonschema-form/

Size: 4724

Language: JavaScript

GitHub Committers

UserMost Recent Commit# Commits

Other Committers

UserEmailMost Recent Commit# Commits

README

react-jsonschema-form

Build Status

A simple React component capable of building HTML forms out of a JSON schema and using Bootstrap semantics by default.

A live playground is hosted on gh-pages.

Table of Contents

Philosophy

react-jsonschema-form is meant to automatically generate a React form based on a JSON Schema. It is a major component in the kinto-admin. If you want to generate a form for any data, sight unseen, simply given a JSON schema, react-jsonschema-form may be for you. If you have a priori knowledge of your data and want a toolkit for generating forms for it, you might look elsewhere.

react-jsonschema-form validates that the data conforms to the given schema, but doesn't prevent the user from inputing data that doesn't fit (for example, stripping non-numbers from a number field, or not letting the user add values to an array that is already “full”.

Installation

Requires React 15.0.0+.

Note: The master branch of the repository reflects ongoing development. Releases are published as tags.

You should never blindly install from master, but rather check what the available stable releases are.

As a npm-based project dependency
m install react-jsonschema-form --save

Note: While the library renders Bootstrap HTML semantics, you have to build/load the Bootstrap styles on your own.

As a script served from a CDN
cript src="https://unpkg.com/react-jsonschema-form/dist/react-jsonschema-form.js"></script>

Source maps are available at this url.

Note: The CDN version does not embed react nor react-dom.

You'll also need to alias the default export property to use the Form component:

t Form = JSONSchemaForm.default;
r
t {default: Form} = JSONSchemaForm;
Usage
rt React, { Component } from "react";
rt { render } from "react-dom";

rt Form from "react-jsonschema-form";

t schema = {
tle: "Todo",
pe: "object",
quired: ["title"],
operties: {
title: {type: "string", title: "Title", default: "A new task"},
done: {type: "boolean", title: "Done?", default: false}



t log = (type) => console.log.bind(console, type);

er((
orm schema={schema}
    onChange={log("changed")}
    onSubmit={log("submitted")}
    onError={log("errors")} />
ocument.getElementById("app"));

That should give something like this (if you took care of loading the standard Bootstrap stylesheet):

Form initialization

Often you'll want to prefill a form with existing data; this is done by passing a formData prop object matching the schema:

t formData = {
tle: "First task",
ne: true


er((
orm schema={schema}
    formData={formData} />
ocument.getElementById("app"));

NOTE: If your form have a single field, pass a single value to formData. ex: formData='Charlie'

WARNING: If you have situations where your parent component can re-render, make sure you listen to the onChange event and update the data you pass to the formData attribute.

Form event handlers
Form submission

You can pass a function as the onSubmit prop of your Form component to listen to when the form is submitted and its data are valid. It will be passed a result object having a formData attribute, which is the valid form data you're usually after:

t onSubmit = ({formData}) => console.log("Data submitted: ",  formData);

er((
orm schema={schema}
    onSubmit={onSubmit} />
ocument.getElementById("app"));
Form error event handler

To react to when submitted form data are invalid, pass an onError handler, which is passed the list of encountered errors:

t onError = (errors) => console.log("I have", errors.length, "errors to fix");

er((
orm schema={schema}
    onError={onError} />
ocument.getElementById("app"));
Form data changes

If you plan on being notified every time the form data are updated, you can pass an onChange handler, which will receive the same args as onSubmit any time a value is updated in the form.

Form field blur events

Sometimes you may want to trigger events or modify external state when a field has been touched, so you can pass an onBlur handler, which will receive the id of the input that was blurred and the field value.

Form field focus events

Sometimes you may want to trigger events or modify external state when a field has been focused, so you can pass an onFocus handler, which will receive the id of the input that is focused and the field value.

Form customization
The uiSchema object

JSONSchema is limited for describing how a given data type should be rendered as a form input component, that's why this lib introduces the concept of UI schema.

A UI schema is basically an object literal providing information on how the form should be rendered, while the JSON schema tells what.

The uiSchema object follows the tree structure of the form field hierarchy, and for each allows to define how it should be rendered:

t schema = {
pe: "object",
operties: {
foo: {
  type: "object",
  properties: {
    bar: {type: "string"}
  }
},
baz: {
  type: "array",
  items: {
    type: "object",
    properties: {
      description: {
        "type": "string"
      }
    }
  }
}



t uiSchema = {
o: {
bar: {
  "ui:widget": "textarea"
},

z: {
// note the "items" for an array
items: {
  description: {
    "ui:widget": "textarea"
  }
}



er((
orm schema={schema}
    uiSchema={uiSchema} />
ocument.getElementById("app"));
Alternative widgets

The uiSchema ui:widget property tells the form which UI widget should be used to render a certain field:

Example:

t uiSchema =  {
ne: {
"ui:widget": "radio" // could also be "select"



er((
orm schema={schema}
    uiSchema={uiSchema}
    formData={formData} />
ocument.getElementById("app"));

Here's a list of supported alternative widgets for different JSONSchema data types:

For boolean fields

Note: To set the labels for a boolean field, instead of using true and false you can set enumNames in your schema. Note that enumNames belongs in your schema, not the uiSchema, and the order is always [true, false].

For string fields String formats

The built-in string field also supports the JSONSchema format property, and will render an appropriate widget by default for the following string formats:

Please note that while standardized, datetime-local and date input elements are not yet supported by Firefox and IE. If you plan on targeting these platforms, two alternative widgets are available:

For number and integer fields

Note: for numbers, min, max and step input attributes values will be handled according to JSONSchema's minimum, maximum and multipleOf values when they're defined.

Disabled fields

The ui:disabled uiSchema directive will disable all child widgets from a given field.

Read-only fields

The ui:readonly uiSchema directive will mark all child widgets from a given field as read-only.

Note: if you're about the difference between a disabled field and a readonly one: marking a field as read-only will render it greyed but its text value will be selectable; disabling it will prevent its value to be selected at all.

Hidden widgets

It's possible to use an hidden widget for a given field by setting the ui:widget uiSchema directive to hidden for this field:

t schema = {
pe: "object",
operties: {
foo: {type: "boolean"}



t uiSchema = {
o: {"ui:widget": "hidden"}

Notes

  • Hiding widgets is only supported for boolean, string, number and integer schema types;
  • An hidden widget takes its value from the formData prop.
File widgets

This library supports a limited form of input[type=file] widgets, in the sense that it will propagate file contents to form data state as data-urls.

There are two ways to use file widgets:

By declaring a string json schema type along a data-url format:

t schema = {
pe: "string",
rmat: "data-url",

By specifying a ui:widget field uiSchema directive as file:

t schema = {
pe: "string",


t uiSchema = {
i:widget": "file",

Multiple files

Multiple files selectors are supported by defining an array of strings having data-url as a format:

t schema = {
pe: "array",
ems: {
type: "string",
format: "data-url",


Note that storing large dataURIs into form state might slow rendering.

File widget input ref

The included FileWidget exposes a reference to the <input type="file" /> element node as an inputRef component property.

This allows you to programmatically trigger the browser's file selector which can be used in a custom file widget.

Object fields ordering

Since the order of object properties in Javascript and JSON is not guaranteed, the uiSchema object spec allows you to define the order in which properties are rendered using the ui:order property:

t schema = {
pe: "object",
operties: {
foo: {type: "string"},
bar: {type: "string"}



t uiSchema = {
i:order": ["bar", "foo"]


er((
orm schema={schema}
    uiSchema={uiSchema} />
ocument.getElementById("app"));

If a guaranteed fixed order is only important for some fields, you can insert a wildcard "*" item in your ui:order definition. All fields that are not referenced explicitly anywhere in the list will be rendered at that point:

t uiSchema = {
i:order": ["bar", "*"]

Array item options
orderable option

Array items are orderable by default, and react-jsonschema-form renders move up/down buttons alongside them. The uiSchema object spec allows you to disable ordering:

t schema = {
pe: "array",
ems: {
type: "string"



t uiSchema = {
i:options":  {
orderable: false


addable option

If either items or additionalItems contains a schema object, an add button for new items is shown by default. You can turn this off with the addable option in uiSchema:

t uiSchema = {
i:options":  {
addable: false


removable option

A remove button is shown by default for an item if items contains a schema object, or the item is an additionalItems instance. You can turn this off with the removable option in uiSchema:

t uiSchema = {
i:options":  {
removable: false


Custom CSS class names

The uiSchema object accepts a classNames property for each field of the schema:

t uiSchema = {
tle: {
classNames: "task-title foo-bar"


Will result in:

 class="field field-string task-title foo-bar" >
abel>
<span>Title*</span>
<input value="My task" required="" type="text">
label>
v>
Custom labels for enum fields

This library supports the enumNames property for enum fields, which allows defining custom labels for each option of an enum:

t schema = {
pe: "number",
um: [1, 2, 3],
umNames: ["one", "two", "three"]

This will be rendered using a select box that way:

ect>
ption value="1">one</option>
ption value="2">two</option>
ption value="3">three</option>
lect>

Note that string representations of numbers will be cast back and reflected as actual numbers into form state.

Disabled attribute for enum fields

This library supports the 'disabled' attribute for enum options. Enum disabled allows disabling options for 'enum' fields.This attribute can be added as a part of uiSchema.

t schema = {
pe: "string",
um: ["one", "two", "three"],


t uiSchema={
i:enumDisabled": ['two'],

This will be rendered using a select box that way:

ect>
ption value="1">one</option>
ption value="2" disabled>two</option>
ption value="3">three</option>
lect>
Multiple choices list

The default behavior for array fields is a list of text inputs with add/remove buttons. Though there are two alternative simpler widgets for common situations like picking elements against a list of choices; typically this maps to a schema having:

Example:

t schema = {
pe: "array",
tle: "A multiple choices list",
ems: {
type: "string",
enum: ["foo", "bar", "fuzz", "qux"],

iqueItems: true

By default, this will automatically render a multiple select box. If you prefer a list of checkboxes, just set the uiSchema ui:widget directive to "checkboxes" for that field:

t uiSchema = {
i:widget": "checkboxes"

Care should be taken when using the required property with arrays. An empty array is sufficient to pass that validation check. If you wish to ensure the user populates the array, you can specify the minimum number of items the user must select with the minItems property.

Example:

t schema = {
pe: "array",
nItems: 2,
tle: "A multiple choices list",
ems: {
type: "string",
enum: ["foo", "bar", "fuzz", "qux"],

iqueItems: true

By default, checkboxes are stacked but if you prefer them inline:

t uiSchema = {
i:widget": "checkboxes",
i:options": {
inline: true


See the “Arrays” section of the playground for cool demos.

Autogenerated widget ids

By default, the lib will generate ids unique to the form for all rendered widgets. But if you plan on using multiple instances of the Form component in a same page, it's wise to declare a root prefix for these, using the ui:rootFieldId uiSchema directive:

t uiSchema = {
i:rootFieldId": "myform"

So all widgets will have an id prefixed with myform.

Form action buttons

You can provide custom buttons to your form via the Form component's children. A default submit button will be rendered if you don't provide children to the Form component.

er((
orm schema={schema}>
<div>
  <button type="submit">Submit</button>
  <button type="button">Cancel</button>
</div>
Form>
ocument.getElementById("app"));

Warning: there should be a button or an input with type="submit" to trigger the form submission (and then the form validation).

Help texts

Sometimes it's convenient to add some text next to a field to guide the end user filling it; this is the purpose of the ui:help uiSchema directive:

t schema = {type: "string"};
t uiSchema = {
i:widget": "password",
i:help": "Hint: Make it strong!"

Help texts work for any kind of field at any level, and will always be rendered immediately below the field component widget(s), but after contextualized errors, if any.

Title texts

Sometimes it's convenient to change title a field; this is the purpose of the ui:title uiSchema directive:

t schema = {type: "string"};
t uiSchema = {
i:widget": "password",
i:title": "Your password"

Description texts

Sometimes it's convenient to change description a field; this is the purpose of the ui:description uiSchema directive:

t schema = {type: "string"};
t uiSchema = {
i:widget": "password",
i:description": "The best password"

Auto focus

If you want to focus on a text input or textarea input/on a widget automatically, just set ui:autofocus uiSchema directive to true.

t schema = {type: "string"};
t uiSchema = {
i:widget": "textarea",
i:autofocus": true

Textarea rows option

You can set initial height of a textarea widget by specifying rows option.

t schema = {type: "string"};
t uiSchema = {
i:widget": "textarea",
i:options": {
rows: 15


Placeholders

Text fields can benefit from placeholders by using the ui:placeholder uiSchema directive:

t schema = {type: "string", format: "uri"};
t uiSchema = {
i:placeholder": "http://"

Fields using enum can also use ui:placeholder. The value will be used as the text for the empty option in the select widget.

t schema = {type: "string", enum: ["First", "Second"]};
t uiSchema = {
i:placeholder": "Choose an option"

Field labels

Field labels are rendered by default. Labels may be omitted by setting the label option to false from ui:options uiSchema directive.

t schema = {type: "string"};
t uiSchema = {
i:options": {
label: false


HTML5 Input Types

If all you need to do is change the input type (for using things like input type=“tel”) you can specify the inputType from ui:options uiSchema directive.

t schema = {type: "string"};
t uiSchema = {
i:options": {
inputType: 'tel'


Form attributes

Form component supports the following html attributes:

m
="edit-form"
assName="form form-wide"
me="awesomeForm"
thod="post"
rget="_blank"
tion="/users/list"
tocomplete="off"
ctype="multipart/form-data"
ceptcharset="ISO-8859-1"
hema={} />
Advanced customization
Field template

To take control over the inner organization of each field (each form row), you can define a field template for your form.

A field template is basically a React stateless component being passed field-related props so you can structure your form row as you like:

tion CustomFieldTemplate(props) {
nst {id, classNames, label, help, required, description, errors, children} = props;
turn (
<div className={classNames}>
  <label htmlFor={id}>{label}{required ? "*" : null}</label>
  {description}
  {children}
  {errors}
  {help}
</div>



er((
orm schema={schema}
    FieldTemplate={CustomFieldTemplate} />,
ocument.getElementById("app"));

If you want to handle the rendering of each element yourself, you can use the props rawHelp, rawDescription and rawErrors.

The following props are passed to a custom field template component:

Note: you can only define a single field template for a form. If you need many, it's probably time to look at custom fields instead.

Array Field Template

Similarly to the FieldTemplate you can use an ArrayFieldTemplate to customize how your arrays are rendered. This allows you to customize your array, and each element in the array.

tion ArrayFieldTemplate(props) {
turn (
<div>
  {props.items.map(element => element.children)}
  {props.canAdd && <button type="button" onClick={props.onAddClick}></button>}
</div>



er((
orm schema={schema}
    ArrayFieldTemplate={ArrayFieldTemplate} />,
ocument.getElementById("app"));

Please see customArray.js for a better example.

The following props are passed to each ArrayFieldTemplate:

The following props are part of each element in items:

Object Field Template

Similarly to the FieldTemplate you can use an ObjectFieldTemplate to customize how your objects are rendered.

tion ObjectFieldTemplate(props) {
turn (
<div>
  {props.title}
  {props.description}
  {props.properties.map(element => <div className="property-wrapper">{element.children}</div>)}
</div>



er((
orm schema={schema}
    ObjectFieldTemplate={ObjectFieldTemplate} />,
ocument.getElementById("app"));

Please see customObject.js for a better example.

The following props are passed to each ObjectFieldTemplate:

The following props are part of each element in properties:

Error List template

To take control over how the form errors are displayed, you can define an error list template for your form. This list is the form global error list that appears at the top of your forms.

An error list template is basically a React stateless component being passed errors as props so you can render them as you like:

tion ErrorListTemplate(props) {
nst {errors} = props;
turn (
<div>
  {errors.map((error, i) => {
    return (
      <li key={i}>
        {error.stack}
      </li>
    );
  })}
</div>



er((
orm schema={schema}
    showErrorList={true}
    ErrorList={ErrorListTemplate} />,
ocument.getElementById("app"));

Note: Your custom ErrorList template will only render when showErrorList is true.

The following props are passed to ErrorList

Id prefix

To avoid collisions with existing ids in the DOM, it is possible to change the prefix used for ids (the default is root).

er((
orm schema={schema}
    idPrefix={"rjsf_prefix"}/>,
ocument.getElementById("app"));

This will render <input id="rjsf_prefix_key"> instead of <input id="root_key">

Custom widgets and fields

The API allows to specify your own custom widget and field components:

Custom widget components

You can provide your own custom widgets to a uiSchema for the following json data types:

t schema = {
pe: "string"


t uiSchema = {
i:widget": (props) => {
return (
  <input type="text"
    className="custom"
    value={props.value}
    required={props.required}
    onChange={(event) => props.onChange(event.target.value)} />
);



er((
orm schema={schema}
    uiSchema={uiSchema} />,
ocument.getElementById("app"));

The following props are passed to custom widget components:

Note: Prior to v0.35.0, the options prop contained the list of options (label and value) for enum fields. Since v0.35.0, it now exposes this list as the enumOptions property within the options object.

Custom component registration

Alternatively, you can register them all at once by passing the widgets prop to the Form component, and reference their identifier from the uiSchema:

t MyCustomWidget = (props) => {
turn (
<input type="text"
  className="custom"
  value={props.value}
  required={props.required}
  onChange={(event) => props.onChange(event.target.value)} />



t widgets = {
CustomWidget: MyCustomWidget


t uiSchema = {
i:widget": "myCustomWidget"


er((
orm
schema={schema}
uiSchema={uiSchema}
widgets={widgets} />
ocument.getElementById("app"));

This is useful if you expose the uiSchema as pure JSON, which can't carry functions.

Note: Until 0.40.0 it was possible to register a widget as object with shape { component: MyCustomWidget, options: {...} }. This undocumented API has been removed. Instead, you can register a custom widget with a React defaultProps property. defaultProps.options can be an object containing your custom options.

Custom widget options

If you need to pass options to your custom widget, you can add a ui:options object containing those properties. If the widget has defaultProps, the options will be merged with the (optional) options object from defaultProps:

t schema = {
pe: "string"


tion MyCustomWidget(props) {
nst {options} = props;
nst {color, backgroundColor} = options;
turn <input style={{color, backgroundColor}} />;


stomWidget.defaultProps = {
tions: {
color: "red"



t uiSchema = {
i:widget": MyCustomWidget,
i:options": {
backgroundColor: "yellow"



enders red on yellow input
er((
orm schema={schema}
    uiSchema={uiSchema} />
ocument.getElementById("app"));

Note: This also applies to registered custom components.

Note: Since v0.41.0, the ui:widget object API, where a widget and options were specified with "ui:widget": {component, options} shape, is deprecated. It will be removed in a future release.

Customizing widgets' text input

All the widgets that render a text input use the BaseInput component internally. If you need to customize all text inputs without customizing all widgets individially, you can provide a BaseInput component in the widgets property of Form (see Custom component registration.

Custom field components

You can provide your own field components to a uiSchema for basically any json schema data type, by specifying a ui:field property.

For example, let's create and register a dumb geo component handling a latitude and a longitude:

t schema = {
pe: "object",
quired: ["lat", "lon"],
operties: {
lat: {type: "number"},
lon: {type: "number"}



efine a custom component for handling the root position object
s GeoPosition extends React.Component {
nstructor(props) {
super(props);
this.state = {...props.formData};


Change(name) {
return (event) => {
  this.setState({
    [name]: parseFloat(event.target.value)
  }, () => this.props.onChange(this.state));
};


nder() {
const {lat, lon} = this.state;
return (
  <div>
    <input type="number" value={lat} onChange={this.onChange("lat")} />
    <input type="number" value={lon} onChange={this.onChange("lon")} />
  </div>
);



efine the custom field component to use for the root object
t uiSchema = {"ui:field": "geo"};

efine the custom field components to register; here our "geo"
ustom field component
t fields = {geo: GeoPosition};

ender the form with all the properties we just defined passed
s props
er((
orm
schema={schema}
uiSchema={uiSchema}
fields={fields} />
ocument.getElementById("app"));

Note: Registered fields can be reused across the entire schema.

Field props

A field component will always be passed the following props:

The registry object

The registry is an object containing the registered custom fields and widgets as well as root schema definitions.

The registry is passed down the component tree, so you can access it from your custom field and SchemaField components.

The formContext object

You can provide a formContext object to the Form, which is passed down to all fields and widgets (including TitleField and DescriptionField). Useful for implementing context aware fields and widgets.

Custom array field buttons

The ArrayField component provides a UI to add, remove and reorder array items, and these buttons use Bootstrap glyphicons. If you don't use glyphicons but still want to provide your own icons or texts for these buttons, you can easily do so using CSS:

yphicon { display: none; }
-add::after { content: 'Add'; }
ay-item-move-up::after { content: 'Move Up'; }
ay-item-move-down::after { content: 'Move Down'; }
ay-item-remove::after { content: 'Remove'; }
Custom SchemaField

Warning: This is a powerful feature as you can override the whole form behavior and easily mess it up. Handle with care.

You can provide your own implementation of the SchemaField base React component for rendering any JSONSchema field type, including objects and arrays. This is useful when you want to augment a given field type with supplementary powers.

To proceed so, pass a fields object having a SchemaField property to your Form component; here's a rather silly example wrapping the standard SchemaField lib component:

rt SchemaField from "react-jsonschema-form/lib/components/fields/SchemaField";

t CustomSchemaField = function(props) {
turn (
<div id="custom">
  <p>Yeah, I'm pretty dumb.</p>
  <SchemaField {...props} />
</div>



t fields = {
hemaField: CustomSchemaField


er((
orm schema={schema}
    uiSchema={uiSchema}
    formData={formData}
    fields={fields} />
ocument.getElementById("app"));

If you're curious how this could ever be useful, have a look at the Kinto formbuilder repository to see how it's used to provide editing capabilities to any form field.

Props passed to a custom SchemaField are the same as the ones passed to a custom field.

Customizing the default fields and widgets

You can override any default field and widget, including the internal widgets like the CheckboxWidget that ObjectField renders for boolean values. You can override any field and widget just by providing the customized fields/widgets in the fields and widgets props:

t CustomCheckbox = function(props) {
turn (
<button id="custom" className={props.value ? "checked" : "unchecked"} onClick={() => props.onChange(!props.value)}>
    {props.value}
</button>



t widgets = {
eckboxWidget: CustomCheckbox


er((
orm schema={schema}
    uiSchema={uiSchema}
    formData={formData}
    widgets={widgets} />
ocument.getElementById("app"));

This allows you to create a reusable customized form class with your custom fields and widgets:

t customFields = {StringField: CustomString};
t customWidgets = {CheckboxWidget: CustomCheckbox};

tion MyForm(props) {
turn <Form fields={customFields} widgets={customWidgets} {...props} />;


er((
yForm schema={schema}
uiSchema={uiSchema}
formData={formData} />
ocument.getElementById("app"));
Custom titles

You can provide your own implementation of the TitleField base React component for rendering any title. This is useful when you want to augment how titles are handled.

Simply pass a fields object having a TitleField property to your Form component:

t CustomTitleField = ({title, required}) => {
nst legend = required ? title + '*' : title;
turn <div id="custom">{legend}</div>;


t fields = {
tleField: CustomTitleField


er((
orm schema={schema}
    uiSchema={uiSchema}
    formData={formData}
    fields={fields} />
ocument.getElementById("app"));
Custom descriptions

You can provide your own implementation of the DescriptionField base React component for rendering any description.

Simply pass a fields object having a DescriptionField property to your Form component:

t CustomDescriptionField = ({id, description}) => {
turn <div id={id}>{description}</div>;


t fields = {
scriptionField: CustomDescriptionField


er((
orm schema={schema}
    uiSchema={uiSchema}
    formData={formData}
    fields={fields} />
ocument.getElementById("app"));
Form data validation
Live validation

By default, form data are only validated when the form is submitted or when a new formData prop is passed to the Form component.

You can enable live form data validation by passing a liveValidate prop to the Form component, and set it to true. Then, everytime a value changes within the form data tree (eg. the user entering a character in a field), a validation operation is performed, and the validation results are reflected into the form state.

Be warned that this is an expensive strategy, with possibly strong impact on performances.

To disable validation entirely, you can set Form's noValidate prop to true.

HTML5 Validation

By default, required field errors will cause the browser to display its standard HTML5 required attribute error messages and prevent form submission. If you would like to turn this off, you can set Form's noHtml5Validate prop to true, which will set noValidate on the form element.

Custom validation

Form data is always validated against the JSON schema.

But it is possible to define your own custom validation rules. This is especially useful when the validation depends on several interdependent fields.

tion validate(formData, errors) {
 (formData.pass1 !== formData.pass2) {
errors.pass2.addError("Passwords don't match");

turn errors;


t schema = {
pe: "object",
operties: {
pass1: {type: "string", minLength: 3},
pass2: {type: "string", minLength: 3},



er((
orm schema={schema}
    validate={validate} />
ocument.getElementById("app"));

Notes:

  • The validate() function must always return the errors object received as second argument.
  • The validate() function is called after the JSON schema validation.
Custom error messages

Validation error messages are provided by the JSON Schema validation by default. If you need to change these messages or make any other modifications to the errors from the JSON Schema validation, you can define a transform function that receives the list of JSON Schema errors and returns a new list.

tion transformErrors(errors) {
turn errors.map(error => {
if (error.name === "pattern") {
  error.message = "Only digits are allowed"
}
return error;
;


t schema = {
pe: "object",
operties: {
onlyNumbersString: {type: "string", pattern: "^\\d*$"},



er((
orm schema={schema}
    transformErrors={transformErrors} />
ocument.getElementById("app"));

Notes:

  • The transformErrors() function must return the list of errors. Modifying the list in place without returning it will result in an error.
Error List Display

To disable rendering of the error list at the top of the form, you can set the showErrorList prop to false. Doing so will still validate the form, but only the inline display will show.

er((
orm schema={schema}
    showErrorList={false} />
ocument.getElementById("app"));

Note: you can also use your own ErrorList

The case of empty strings

When a text input is empty, the field in form data is set to undefined. String fields that use enum and a select widget will have an empty option at the top of the options list that when selected will result in the field being undefined.

One consequence of this is that if you have an empty string in your enum array, selecting that option in the select input will cause the field to be set to undefined, not an empty string.

If you want to have the field set to a default value when empty you can provide a ui:emptyValue field in the uiSchema object.

Styling your forms

This library renders form fields and widgets leveraging the Bootstrap semantics. That means your forms will be beautiful by default if you're loading its stylesheet in your page.

You're not necessarily forced to use Bootstrap; while it uses its semantics, it also provides a bunch of other class names so you can bring new styles or override default ones quite easily in your own personalized stylesheet. That's just HTML after all :)

If you're okay with using styles from the Bootstrap ecosystem though, then the good news is that you have access to many themes for it, which are compatible with our generated forms!

Here are some examples from the playground, using some of the Bootswatch free themes:

Last, if you really really want to override the semantics generated by the lib, you can always create and use your own custom widget, field and/or schema field components.

Schema definitions and references

This library partially supports inline schema definition dereferencing, which is Barbarian for avoiding to copy and paste commonly used field schemas:


efinitions": {
"address": {
  "type": "object",
  "properties": {
    "street_address": { "type": "string" },
    "city":           { "type": "string" },
    "state":          { "type": "string" }
  },
  "required": ["street_address", "city", "state"]
}

ype": "object",
roperties": {
"billing_address": { "$ref": "#/definitions/address" },
"shipping_address": { "$ref": "#/definitions/address" }


(Sample schema courtesy of the Space Telescope Science Institute)

Note that it only supports local definition referencing, we do not plan on fetching foreign schemas over HTTP anytime soon. Basically, you can only reference a definition from the very schema object defining it.

Property dependencies

This library supports conditionally making fields required based on the presence of other fields.

Unidirectional

In the following example the billing_address field will be required if credit_card is defined.


ype": "object",

roperties": {
"name": { "type": "string" },
"credit_card": { "type": "number" },
"billing_address": { "type": "string" }


equired": ["name"],

ependencies": {
"credit_card": ["billing_address"]


Bidirectional

In the following example the billing_address field will be required if credit_card is defined and the credit_card field will be required if billing_address is defined making them both required if either is defined.


ype": "object",

roperties": {
"name": { "type": "string" },
"credit_card": { "type": "number" },
"billing_address": { "type": "string" }


equired": ["name"],

ependencies": {
"credit_card": ["billing_address"],
"billing_address": ["credit_card"]


(Sample schemas courtesy of the Space Telescope Science Institute)

Schema dependencies

This library also supports modifying portions of a schema based on form data.

Conditional

ype": "object",

roperties": {
"name": { "type": "string" },
"credit_card": { "type": "number" }


equired": ["name"],

ependencies": {
"credit_card": {
  "properties": {
    "billing_address": { "type": "string" }
  },
  "required": ["billing_address"]
}


In this example the billing_address field will be displayed in the form if credit_card is defined.

(Sample schemas courtesy of the Space Telescope Science Institute)

Dynamic

The JSON Schema standard says that the dependency is triggered if the property is present. However, sometimes it's useful to have more sophisticated rules guiding the application of the dependency. For example, maybe you have three possible values for a field, and each one should lead to adding a different question. For this, we support a very restricted use of the oneOf keyword.


itle": "Person",
ype": "object",
roperties": {
"Do you have any pets?": {
  "type": "string",
  "enum": [
    "No",
    "Yes: One",
    "Yes: More than one"
  ],
  "default": "No"
}

equired": [
"Do you have any pets?"

ependencies": {
"Do you have any pets?": {
  "oneOf": [
    {
      "properties": {
        "Do you have any pets?": {
          "enum": [
            "No"
          ]
        }
      }
    },
    {
      "properties": {
        "Do you have any pets?": {
          "enum": [
            "Yes: One"
          ]
        },
        "How old is your pet?": {
          "type": "number"
        }
      },
      "required": [
        "How old is your pet?"
      ]
    },
    {
      "properties": {
        "Do you have any pets?": {
          "enum": [
            "Yes: More than one"
          ]
        },
        "Do you want to get rid of any?": {
          "type": "boolean"
        }
      },
      "required": [
        "Do you want to get rid of any?"
      ]
    }
  ]
}


In this example the user is prompted with different follow-up questions dynamically based on their answer to the first question.

Note that this is quite far from complete oneOf support!

In these examples, the “Do you have any pets?” question is validated against the corresponding property in each schema in the oneOf array. If exactly one matches, the rest of that schema is merged with the existing schema.

JSON Schema supporting status

This component follows JSON Schema specs. Due to the limitation of form widgets, there are some exceptions as follows:

Tips and tricks
Contributing
Coding style

All the JavaScript code in this project conforms to the prettier coding style. A command is provided to ensure your code is always formatted accordingly:

m run cs-format

The cs-check command ensures all files conform to that style:

m run cs-check
Development server
m start

A live development server showcasing components with hot reload enabled is available at localhost:8080.

If you want the development server to listen on another host or port, you can use the RJSF_DEV_SERVER env variable:

SF_DEV_SERVER=0.0.0.0:8000 npm start
Tests
m test
TDD
m run tdd
Releasing
it package.json # update version number
t commit -m "Bump version $VERSION"
t tag v$VERSION
m run dist
m publish
t push --tags origin
FAQ
Q: Does rjsf support oneOf, anyOf, multiple types in an array, etc.?

A: Not yet (except for a special case where you can use oneOf in schema dependencies), but perhaps you will be the person whose PR will finally add the feature in a way that gets merged. For inspiration, see #329 or #417. See also: #52, #151, #171, #200, #282, #302, #330, #430, #522, #538, #551, #552, or #648.

Q: Will react-jsonschema-form support Material, Ant-Design, Foundation, or [some other specific widget library or frontend style]?

A: Probably not. We use Bootstrap v3 and it works fine for our needs. We would like for react-jsonschema-form to support other frameworks, we just don't want to support them ourselves. Ideally, these frontend styles could be added to react-jsonschema-form with a third-party library. If there is a technical limitation preventing this, please consider opening a PR. See also: #91, #99, #125, #237, #287, #299, #440, #461, #546, #555, #626, and #623.

License

Apache 2


This work is supported by the National Institutes of Health's National Center for Advancing Translational Sciences, Grant Number U24TR002306. This work is solely the responsibility of the creators and does not necessarily represent the official views of the National Institutes of Health.