📖 US Forms System Documentation ➡️ Customizing the library
The US Forms System builds a React application of a form, and determines which React components to render based on the description of the form in the form configuration file.
At the top level, rjsf uses a Form
component to take the schema inputs and render a hierarchy of components for each field of the form:
- Fields generally match the
type
attribute in aschema
object. There are object fields, array fields, number fields, boolean fields, and string fields. Except for arrays and objects, the fields render a label (viaFieldTemplate
) and a widget. To specify a particular field, set theui:field
property to a specific field. - A widget is the html input element that accepts data from the user. To specify a particular widget, set the
ui:widget
property totext
,email
,checkbox
,radio
,select
, andtextarea
. While there are many widgets provided by rjsf, the defaults are overwritten with these versions.
The Form
component is the only React component that you need to manually render in your application. All other components are automatically determined based on the form config. For more information, see "Create required files."
{
type: 'string'
}
The two Field
components determine which fields and widgets to render. SchemaField
uses the two schemas the library accepts, schema
and uiSchema
, to determine what other Field
component to render. The example chose StringField
because the schema type was string
. The StringField
component then rendered TextWidget
, based on schema
and uiSchema
, because the only information provided was that the field is a string (the default widget type).
<SchemaField>
<StringField>
<FieldTemplate>
<TextWidget/>
</FieldTemplate>
</StringField>
</SchemaField>
{
type: 'string',
enum: ['first', 'second', 'third']
}
The hierarchy for this field uses SelectWidget
instead of TextWidget
, because StringField
detected the enum
property in the schema.
<SchemaField>
<StringField>
<FieldTemplate>
<SelectWidget/>
</FieldTemplate>
</StringField>
</SchemaField>
While in most cases a field component is responsible for rendering a label and a widget, for object
and array
schema types, the field component renders additional field components for each of the elements they contain.
This is an object
schema with two string fields.
{
type: 'object',
properties: {
field1: {
type: 'string'
},
field2: {
type: 'string'
}
}
}
The ObjectField
component renders a SchemaField
component for each of its properties. Those properties are both string
types, so it looks like the first hierarchy, but nested.
<SchemaField>
<ObjectField>
<SchemaField>
<StringField>
<FieldTemplate>
<TextWidget/>
</FieldTemplate>
</StringField>
</SchemaField>
<SchemaField>
<StringField>
<FieldTemplate>
<TextWidget/>
</FieldTemplate>
</StringField>
</SchemaField>
</ObjectField>
</SchemaField>
ArrayField
renders a SchemaField
component for each item in the array. The library only uses the array field where each item is an object type schema.
{
type: 'array',
items: {
type: 'object',
properties: {
field1: {
type: 'string'
},
field2: {
type: 'string'
}
}
}
}
In order for each component to know what to render, field components pass a collection of props down through the component hierarchy. Most are passed to widget components.
name
: The property name of the current field. For example, the object schema above would be namedfield1
.required
: If the field is required or not (i.e. the property name is in the schema'srequired
array).schema
: The schema for the specific field.uiSchema
: The ui schema for this field. See "About theuiSchema
field component."errorSchema
: An object that contains the list of errors for the current field and any child properties, if the field is an array or object.idSchema
: An object that contains the field IDs for the current field and any child properties. The library generates IDs for each field by joining each property name with an underscore.formData
: The actual data entered for the field so far.onChange
: The function that's called when data changes. See "About theonChange
field component."onBlur
: The function that's called when focus is lost on a widget.
When a user enters data, each widget calls onChange
. Each component in the hierarchy passes an onChange
handler to child fields. When child data changes, the component combines it with the rest of the data and calls the onChange
prop passed to it from its parent.
{
type: 'object',
properties: {
field1: {
type: 'string'
}
}
}
In this example:
- The user types 'a'.
- The
TextWidget
for field1 callsonChange
with 'a'. - The
onChange
property came from the parentObjectField
component, which puts 'a' in an object asfield1
({ field1: 'a' }
), then calls theonChange
prop it was passed. - When it reaches the top-level
Form
component, rjsf runs the JSON Schema validation and passes the results through the component hierarchy.
Similar to Redux, all state is kept in the Form
component, or the root of the form. All data processing and validation happens in Form
, or is triggered by hooks provided by Form
. The us-forms-system code built on top of this processes the schemas and form data in Redux, triggered by events provided by Form
.
Along with the regular JSON Schema, a UI schema for UI-specific options that don't fit within the JSON Schema standard is also optionally defined for each field. The UI schema is passed to the form config file as an object, uiSchema
, for each field. For more information, see "Understanding the uiSchema
object."