Skip to content

Commit

Permalink
Improve content on the form config (#186)
Browse files Browse the repository at this point in the history
* Separate out advanced information on how the form config works, and create new content at a beginner level for basic information you need to know about creating a form config

* Move to new customization map

* Update links after move

* Rename new conceptual topic

* Rename map

* Update main README after renames and moves

* Rename again

* Copy edits

* Update shortdesc cc @annekainicUSDS

* Remove these sections

* Not "our"
  • Loading branch information
annekainicUSDS authored Jul 24, 2018
1 parent dc43545 commit 4d69ee6
Show file tree
Hide file tree
Showing 7 changed files with 206 additions and 163 deletions.
4 changes: 3 additions & 1 deletion docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,6 @@
- [Available widgets](building-a-form/available-widgets.md)
- [Common definitions](building-a-form/common-definitions.md)
- [Common patterns for building forms](building-a-form/common-patterns-for-building-forms.md)
- [Creating custom fields and widgets](building-a-form/creating-custom-fields-and-widgets.md)
- [Customizing the library](customizing-the-library/README.md)
- [About the React component hierarchy](customizing-the-library/about-the-react-component-hierarchy.md)
- [Creating custom fields and widgets](customizing-the-library/creating-custom-fields-and-widgets.md)
4 changes: 0 additions & 4 deletions docs/building-a-form/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,4 @@ Definitions are pieces of the form config that can be dropped in to represent sp

Some forms require custom validation, styles, or conditional information based on user input. Use these patterns to address those needs.

### [Creating custom fields and widgets](creating-custom-fields-and-widgets.md)

The US Forms System lets you build web-based forms using React and the JSON Schema standard.

[Back to *US Forms System Documentation*](docs/README.md)
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ Require any field. Validation is included.

#### Usage guidelines

For guidance on requiring fields or components, see the example in "[Building a simple form](https://github.com/usds/us-forms-system/blob/master/docs/building-a-form/creating-a-form-config-file.md#building-a-simple-form)."
For information on requiring fields or components, see "[About the schema and uiSchema objects](https://github.com/usds/us-forms-system/blob/master/docs/building-a-form/about-the-schema-and-uischema-objects)."

### Contextual error message

Expand Down
172 changes: 16 additions & 156 deletions docs/building-a-form/creating-a-form-config-file.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,167 +7,27 @@ Your form is generated from a JSON Schema configuration file called `form.js`, a

### In this guide

- [About the `Form` component, fields, and widgets](#about-the-form-component-fields-and-widgets)
- [Example schema: `string` object](#example-schema-string-object)
- [Example schema: `string` with `enum` property](#example-schema-string-with-enum-property)
- [Example schema: `object`](#example-schema-object)
- [Example schema: `ArrayField`](#example-schema-arrayfield)
- [Field component props](#field-component-props)
- [About the `onChange` field component](#about-the-onchange-field-component)
- [About the `uiSchema` field component](#about-the-uischema-field-component)
- [Elements of the form config](#elements-of-the-form-config)
- [How React components are rendered](#how-react-components-are-rendered)

### About the `Form` component, fields, and widgets
### Elements of the form config

At the top level, rjsf uses a `Form` component to take the schema inputs and render a hierarchy of components for each field rendered on the form:
The form config itself is an object with many properties that determine how your form is rendered. It must contain these elements:
- Top level information about the form, such as title, URL, and whether or not certain features are enabled
- Nested objects for each `chapter` of the form (if you're building a multi-page form). Within each `chapter`, additional nested objects for each `page` within that `chapter`. For more information, see "[Supporting multi-page forms](../customizing-the-library/creating-custom-fields-and-widgets#supporting-multi-page-forms)."
- Top-level title and URL information about each `page` of the form, as well as 2 essential objects:
- `schema`: Describes the form fields and the type of data each field accepts
- `uiSchema`: Describes all UI elements of the form fields, such as label text, error message text, or CSS classes

- *Fields* generally match the `type` attribute in a `schema` object. There are object fields, array fields, number fields, boolean fields, and string fields. Except for arrays and objects, the fields render a label (via `FieldTemplate`) and a widget. To specify a particular field, set the `ui: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 to [`text`](available-widgets.md#textwidget), [`email`](available-widgets.md#emailwidget), [`checkbox`](available-widgets.md#checkboxwidget), [`radio`](available-widgets.md#radiowidget), [`select`](available-widgets.md#selectwidget), and `textarea`. While there are many widgets provided by rjsf, the defaults are overwritten with these versions.
The `schema` and `uiSchema` contain the essential information to build all of the form fields. For more information, see "[About the `schema` and `uiSchema` objects](about-the-schema-and-uischema-objects)." For a comprehensive example of a form config, with descriptions of the main properties you might include, see "[Quick Start: Example `form.js` file](quick-start-example-formjs-file.md)".

##### Example schema: `string` object
### How React components are rendered

```
{
type: 'string'
}
```
The US Forms System code uses the form config to determine which React components to render in order to build your form, usually automatically. React components require props to render properly. These are passed down through the top-level `Form` component, which takes the entire form config itself as a prop. The `Form` component is also connected to the store, so it has access to the form data as well.

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).
You rarely need to create or interact with React components directly to use this library, except in these cases:

```
<SchemaField>
<StringField>
<FieldTemplate>
<TextWidget/>
</FieldTemplate>
</StringField>
</SchemaField>
```
- You must manually add the top level `Form` component for every form. For more information, see "[Create required files](../getting-started/installing-the-us-forms-system-in-an-existing-application#create-required-files)."
- You may need to build a custom React component that isn't included in the library by default, such as for the introduction and review pages, or for special content that might appear on each a particular form page. For more information, see "[Creating custom fields and widgets](../customizing-the-library/creating-custom-fields-and-widgets)."

##### Example schema: `string` with `enum` property

```
{
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.

##### Example schema: `object`

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>
```

##### Example schema: `ArrayField`

`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'
}
}
}
}
```

### Field component props

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 named `field1`.
- `required`: If the field is required or not (i.e. the property name is in the schema's `required` array).
- `schema`: The schema for the specific field.
- `uiSchema`: The ui schema for this field. See "[About the `uiSchema` field component](#about-the-uischema-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 the `onChange` field component](#about-the-onchange-field-component)."
- `onBlur`: The function that's called when focus is lost on a widget.

##### About the `onChange` field component

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:

1. The user types 'a'.
2. The `TextWidget` for field1 calls `onChange` with 'a'.
3. The `onChange` property came from the parent `ObjectField` component, which puts 'a' in an object as `field1` (`{ field1: 'a' }`), then calls the `onChange` prop it was passed.
4. 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`.

##### About the `uiSchema` field component

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](about-the-schema-and-uischema-objects.md#understanding-the-uischema-object)."

[Back to *Building a Form*](README.md)
For more information, see "[About the component hierarchy](../how-the-library-works/about-the-component-hierarchy)."
11 changes: 11 additions & 0 deletions docs/customizing-the-library/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Customizing the library

### [About the React component hierarchy](about-the-react-component-hierarhcy.md)

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.

### [Creating custom fields and widgets](creating-custom-fields-and-widgets.md)

You can customize the base library to satisfy the unique requirements of your particular form.

[Back to *US Forms System Documentation*](/docs/README.md)
172 changes: 172 additions & 0 deletions docs/customizing-the-library/about-the-react-component-hierarhcy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
# About the React component hierarchy

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.

### In this guide

- [About the `Form` component, fields, and widgets](#about-the-form-component-fields-and-widgets)
- [Example schema: `string` object](#example-schema-string-object)
- [Example schema: `string` with `enum` property](#example-schema-string-with-enum-property)
- [Example schema: `object`](#example-schema-object)
- [Example schema: `ArrayField`](#example-schema-arrayfield)
- [Field component props](#field-component-props)
- [About the `onChange` field component](#about-the-onchange-field-component)
- [About the `uiSchema` field component](#about-the-uischema-field-component)

### About the `Form` component, fields, and widgets

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 a `schema` object. There are object fields, array fields, number fields, boolean fields, and string fields. Except for arrays and objects, the fields render a label (via `FieldTemplate`) and a widget. To specify a particular field, set the `ui: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 to `text`, `email`, `checkbox`, `radio`, `select`, and `textarea`. 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](../getting-started/installing-the-us-forms-system-in-an-existing-application#create-required-files)."

##### Example schema: `string` object

```
{
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>
```

##### Example schema: `string` with `enum` property

```
{
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.

##### Example schema: `object`

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>
```

##### Example schema: `ArrayField`

`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'
}
}
}
}
```

### Field component props

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 named `field1`.
- `required`: If the field is required or not (i.e. the property name is in the schema's `required` array).
- `schema`: The schema for the specific field.
- `uiSchema`: The ui schema for this field. See "[About the `uiSchema` field component](#about-the-uischema-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 the `onChange` field component](#about-the-onchange-field-component)."
- `onBlur`: The function that's called when focus is lost on a widget.

##### About the `onChange` field component

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:

1. The user types 'a'.
2. The `TextWidget` for field1 calls `onChange` with 'a'.
3. The `onChange` property came from the parent `ObjectField` component, which puts 'a' in an object as `field1` (`{ field1: 'a' }`), then calls the `onChange` prop it was passed.
4. 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`.

##### About the `uiSchema` field component

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](../building-a-form/about-the-schema-and-uischema-objects.md#understanding-the-uischema-object)."

[Back to *Building a Form*](README.md)
Loading

0 comments on commit 4d69ee6

Please sign in to comment.