Jagat Jeevan Sahoo
UI Developer @ThoughtWorks A tech enthusiast
Data driven way for creating and managing React forms.
Document is for v3.2.1
Philosophy:
npm install @rjsf/core --save
import Form from "@rjsf/core";
Latest Reactjsonformschema version require 16+ for React. For React 15, use 1.x version of reactjsonformschema
import Form from "@rjsf/core";
const schema = {
title: "Test form", // Title of the form
description: "Exploring React json schema form", // Description of the form
type: "string", // type of the field
enum: ["one", "two", "three"], // Values the field can have
};
<Form
schema={schema}
uiSchema={uiSchema}
formData={formData}
onChange={(e) => setFormData(e.formData)}
onSubmit={onSubmit}
onError={onError}
/>
The schema is the crux of the rjsf. This is the json which represents the form. Below is the sample for the same.
const schema = {
title: “Here goes the title of the form”,
type: “object”,
properties: {
name: {
type: “string”,
enum: [“name”, “age”, designation]
enumNames: [“Name”, “Age as on 01/01/2020”, “Current designation”]
},
age: {
type: “number”,
enum: [1,2,3,4,5,6,7,8,9]
}
},
required: [“name”],
additionalProperties: {
type: “number”,
enum: [1,2,3]
}
};
<Form schema={schema} />
This is for the ui. Here we override the values as well as any UI level changes / additions are done.
const uiSchema = {
classNames: “custom-css-class-for-form”,
name: {
classNames: “custom-class-for-name-element”
},
“ui:title”: “This is going to override the title value”,
“ui:description”: “This would override the description value”,
“ui:order”: [“age”, “name”], // Defines order of display
};
This is helpful in initialisation of the form.
const schema = {
type: “object”,
properties: {
title: { type: “string” },
done: { type: “boolean” }
}
};
const formData = {
title : “String value for title key”,
done: true
}
<Form schema={schema} formData={formData} />
Note:
There are events such as “onChange”, “onError”, “onSubmit” and “onBlur” on the form component.
By default, form is an uncontrolled component, to make it controlled, we have to pass onChange method like below.
const [formData, setFormData] = useState(props.data);
<Form
formData={formData}
onChange={e => setFormData(e.formData)}
schema={schema}
/>
Json schema form can to define dependencies of fields. So on change of gender, relation would be checked.
Const schema = {
type: “object”,
properties: {
relation: { type: “string”, enum: [“father”, “mother” ]}
gender: { type: “string”, enum: [“male”, “female”, “other” ]}
},
dependencies: {
“gender”: [“relation”],
}
}
There could be bi-directional dependencies. In that case, have it under dependencies. The library also provides a section of the form to be changed depending upon what is selected. So on change of gender, relation would be validated, and vice-versa.
Const schema = {
type: “object”,
properties: {
relation: { type: “string”, enum: [“father”, “mother” ]}
gender: { type: “string”, enum: [“male”, “female”, “other” ]}
},
dependencies: {
“gender”: [“relation”],
“relation”: [“gender”]
}
}
There could be bi-directional dependencies. In that case, have it under dependencies. The library also provides a section of the form to be changed depending upon what is selected.
Modifying some parts of the form depending upon some change in other fields
Const schema = {
type: “object”,
properties: {
name: { type: “string” },
credit_card_number: { type: “number” }
},
dependencies: {
“credit_card_number”: {
properties: { “billing_address”: { type: “string” } },
required: [“billing_address”]
}
}
}
Const schema = {
type: “object”,
properties: {
“Do you have any pets ?”: { type: “string”, enum: [“none”, “one”, “more than one”], default: “none” },
required: [“Do you have any pets ?”]
},
dependencies: {
“Do you have any pets ?”: {
“oneOf”: [
properties: {
“Do you have any pets ?” : { enum: [ “none” ] },
},
properties: {
“Do you have any pets ?” : { enum: [ “one” ] },
“How old is your pet”: { type: “number” }
},
properties: {
“Do you have any pets ?” : { enum: [ “more than one” ] },
“Do you want to get rid of any”: { type: “number” },
required: [“Do you want to get rid of any”]
},
]
}
}
}
When you have a section which needs to be repeated, or referred, you can use the references of a section as below
const schema = {
definitions: {
address: {
type: object,
properties: {
street_address: { type: “string” },
pincode: { type: “number” }
},
required: [“street_address”, “pincode”]
}
},
type: “object”,
billing_address: { “$ref”: “#/definitions/address” },
permanent_address: { “$ref”: “#definitions/address” }
};
oneOf
Const schema = {
type: “object”,
oneOf: [{
properties: { typeOf: { type: “string”, enum: [“none”, “oneOf”] } }
required: [“typeOf”]
}, {
properties: { name: { type: “string”}, age: { type: “number” } },
required: [“name”]
}]
}
Similarly, we have anyOf and allOf in the same fashion
The “ui:widget” property in “uiSchema” tells which component to render.
const schema = {
type: “object”,
properties: { done: “boolean” }
}
const uiSchema = {
done: { ui:widget: radio }
}
List of data types and ui:widgets available
Boolean:
To set the labels on the fields, use enumNames in the schema. The order is always [true, false]
Formats given by the browser, we can use the format property in the schema. Below are the formats supported
For string widget, we can have the following. Default value : text
Const schema = {
type: object,
properties : { email: { type: “string”, format: “email” } },
required: [“email”]
}
Note : If the minimum, maximum and multipleOf is specified, then the “min”, “max” and “step” values are taken.
Mention in the uiSchema to have hidden values in the form. Hidden values are supported for boolean, string, number and integers
This is basically <input type=“file” /> It would propagate the file contents to the data-urls
2 ways to declare:
And for multiple files,
Schema would be
Const schema = {
type: array,
items: { type: “string”, format: “data-url” }
}
const uiSchema = {
"ui:options": { accept: ".pdf" }
};
React json schema form uses “ajv” validator by default.
By default the form is validated only when the form is submitted, if we want liveValidation, we have to use the attribute “liveValidate” on the form component. This is an expensive strategy.
The form uses html5 validation. This is again depends on the browser support. We can disable html5Validation with “noHtml5Validate”.
<Form schema={schema} liveValidate />
Const validate = (formData, errors) => {
if(formData.pass1 !== formData.pass2) {
errors.pass2.addError(“Password do not match”)
}
return errors;
}
Const schema = {
type: “object”,
properties: {
pass1: {type: “string”, minLength: 3},
pass2: {type: “string”, minLength: 3}
}
}
<Form schema={schema} validate={validate} />
Const CustomCheckbox = props => {
const {options, value} = props;
return (
// Component code.
<button>{String(value)}</button>
)
}
CustomCheckbox.defaultProps = { options: { background: “blue” } };
Const schema = { type: “boolean”, default: true };
Const uiSchema = { “ui:widget”: “checkbox” };
Const widgets = { CheckboxWidget: CustomCheckbox }
<Form schema={schema} uiSchema={uiSchema} widgets={widgets} />
Majorly we would require our component rather than just HTML elements. In such cases, custom widgets would come into the picture.
Widget: That represents HTML tags like input, select, etc.
Field: This usually wraps one or more widgets and handles the state of the widgets.
Likewise, each of the widgets can be mapped. Below is the default widget that can be overridden like the above code.
In the widgets, the below props are passed by default by the library.
Field props
By Jagat Jeevan Sahoo
A data driven way of creating react forms. Handling errors and skinning.