diff --git a/docs/README.md b/docs/README.md index 22ca9b9..417ed4e 100644 --- a/docs/README.md +++ b/docs/README.md @@ -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) diff --git a/docs/building-a-form/README.md b/docs/building-a-form/README.md index f6245b2..4da3e8d 100644 --- a/docs/building-a-form/README.md +++ b/docs/building-a-form/README.md @@ -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) diff --git a/docs/building-a-form/available-form-features-and-usage-guidelines.md b/docs/building-a-form/available-form-features-and-usage-guidelines.md index 6f7054b..d379492 100644 --- a/docs/building-a-form/available-form-features-and-usage-guidelines.md +++ b/docs/building-a-form/available-form-features-and-usage-guidelines.md @@ -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 diff --git a/docs/building-a-form/creating-a-form-config-file.md b/docs/building-a-form/creating-a-form-config-file.md index 990df9c..13a8e17 100644 --- a/docs/building-a-form/creating-a-form-config-file.md +++ b/docs/building-a-form/creating-a-form-config-file.md @@ -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: -``` - - - - - - - -``` +- 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. - -``` - - - - - - - -``` - -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. - -``` - - - - - - - - - - - - - - - - - - -``` - -##### 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)." diff --git a/docs/customizing-the-library/README.md b/docs/customizing-the-library/README.md new file mode 100644 index 0000000..e03f385 --- /dev/null +++ b/docs/customizing-the-library/README.md @@ -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) diff --git a/docs/customizing-the-library/about-the-react-component-hierarhcy.md b/docs/customizing-the-library/about-the-react-component-hierarhcy.md new file mode 100644 index 0000000..3efe91c --- /dev/null +++ b/docs/customizing-the-library/about-the-react-component-hierarhcy.md @@ -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). + +``` + + + + + + + +``` + +##### 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. + +``` + + + + + + + +``` + +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. + +``` + + + + + + + + + + + + + + + + + + +``` + +##### 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) diff --git a/docs/building-a-form/creating-custom-fields-and-widgets.md b/docs/customizing-the-library/creating-custom-fields-and-widgets.md similarity index 95% rename from docs/building-a-form/creating-custom-fields-and-widgets.md rename to docs/customizing-the-library/creating-custom-fields-and-widgets.md index fc1eed0..4d9cf99 100644 --- a/docs/building-a-form/creating-custom-fields-and-widgets.md +++ b/docs/customizing-the-library/creating-custom-fields-and-widgets.md @@ -1,5 +1,7 @@ # Creating custom fields and widgets +You can customize the base library to satisfy the unique requirements of your particular form. + ### In this guide - [How the us-forms-system uses rjsf](#how-us-forms-system-uses-rjsf) @@ -8,7 +10,7 @@ ### How us-forms-system uses rjsf -The us-forms-system code uses rjsf to render form fields, but it builds a scaffolding on top of it to support multi-page forms and our common form patterns. Additionally, us-forms-system uses rjsf to create a form configuration spec that allows devs to specify the structure of one of our multi-page forms. +The us-forms-system code uses rjsf to render form fields, but it builds a scaffolding on top of it to support multi-page forms and common form patterns. Additionally, us-forms-system uses rjsf to create a form configuration spec that allows developers to specify the structure of a multi-page form. ##### Customizing fields, widgets, and events from rjsf