📖 US Forms System Documentation ➡️ Building a Form
These form features are available in the US Forms System library. We've provided information about how to implement them in your form.
- Form instructions
- Form footer
- Progress bar
- Title
- Date
- Alerts
- Radio button group
- Checkbox group
- Required field
- Contextual error message
- Duplicate field validation
- Conditional form fields
- Sequential duplicate form groups
- Review page
- Required checkbox before form submission
- Remote error and event monitoring
This widget allows you to provide important information, warnings, or step-by-step instructions to users before they fill out a form.
Unlike most components, the Introduction
React component is in the US Forms System Starter App at https://github.com/usds/us-forms-system-starter-app/blob/master/js/components/Introduction.jsx, not the library itself.
To include the component, set the formConfig.introduction
property to a reference to that component. Edit the HTML inside the component to change the content. For example:
import Introduction from '../components/Introduction.jsx';
const formConfig = {
…
introduction: Introduction,
…
};
This widget appears at the bottom of every page of a multi-page form. It is not required.
To define footer content, create a React component that renders HTML to act as a footer. The US Forms System Starter App does not include a footer, but the design of this component would be very similar to the Introduction component that the starter app contains. For example:
import Footer from '../components/Footer.jsx';
const formConfig = {
…
footer: Footer,
…
};
For the code implementation, see FormApp.jsx.
The SegmentedProgressBar
component calculates the number of chapters completed and displays them in a horizontal stack of blocks. It indicates to the user how much of a multi-chapter or multi-page form they've completed. It includes:
- A non-interactive, sectioned progress bar
- A number to indicate how many pages there are within each section
- The title of that section
In formConfig
, define your form's chapters and the pages contained inside each chapter. To add a progress bar to a multi-page form, create chapters with a single page each. We don't recommend including a progress bar on single-page forms.
US Forms System includes the progress bar by default, and will display automatically when the chapters and pages are defined. To remove the progress bar, edit the FormNav.jsx
component to remove the defined SegmentedProgressBar
in the HTML.
For the code implementation, see:
The Title and Subtitle represent the name and form number, respectively. The subtitle displays near the form title.
Define the title and subtitle in formConfig
. For example:
const formConfig = {
…
title: 'Apply for Health Care',
subtitle: 'Form 10-10EZ',
…
};
For the code implementation, see FormTitle.jsx.
Defines a date picker with validations.
Define these fields in the schema
and then reference them in the uiSchema
. These date field definitions are available:
For example:
import currentOrPastDate from '../definitions/currentOrPastDate.js';
const formConfig = {
…
schema: {
type: 'object',
required: [ 'serviceDate' ],
properties: {
serviceDate: 'string'
}
},
uiSchema: {
serviceDate: currentOrPastDate('Service Date'),
}
…
};
Alerts are included automatically in fields that include validation. Taken from USWDS, alerts appear in several color variations, with or without icons, to indicate a warning, an error, or contextual information.
For examples of how alerts are used, see https://github.com/usds/us-forms-system/tree/master/src/js/widgets.
A group of options where the user can only select a single item.
The data for a group of radio buttons is similar to the data for a select field (i.e., string
type with an enum
property), which means the SelectWidget
will be rendered by default.
To override the SelectWidget
, pass 'ui:widget': 'radio'
to your uiSchema
for that field. To specify different label text for each option, pass 'ui:options'
to uiSchema
.
Your config for a question where the answer is selected from a group of radio buttons might look like this:
schema: {
type: 'object',
properties: {
favoriteAnimal: {
type: 'string',
enum: ['dog', 'cat', 'octopus', 'sloth']
}
}
},
uiSchema: {
'ui:widget': 'radio',
'ui:options': {
labels: {
dog: 'Dog',
cat: 'Cat',
octopus: 'Octopus',
sloth: 'Sloth'
}
}
}
For the code implementation, see RadioWidget
.
A group of options where the user can select multiple items.
Each individual checkbox is used to store boolean
data. To include a group of checkboxes, include separate fields for each checkbox, with type: 'boolean'
passed to the schema
.
Your config for a group of checkboxes might look like this:
schema: {
type: 'object',
properties: {
'view:booksRead': {
type: 'object',
properties: {
hasReadPrideAndPrejudice: { type: 'boolean' },
hasReadJaneEyre: { type: 'boolean' },
hasReadGreatGatsby: { type: 'boolean' },
hasReadBuddenbrooks: { type: 'boolean' }
}
}
}
},
uiSchema: {
'view:booksRead': {
'ui:title': 'Which books have you read?',
'ui:description': 'You may check more than one.',
hasReadPrideAndPrejudice: {
'ui:title': 'Pride and Prejudice by Jane Austen'
},
hasReadJaneEyre: {
'ui:title': 'Jane Eyre by Charlotte Brontë'
},
hasReadGreatGatsby: {
'ui:title': 'The Great Gatsby by F. Scott Fitzgerald'
},
hasReadBuddenbrooks: {
'ui:title': 'Buddenbrooks by Thomas Mann'
}
}
}
For the code implementation, see CheckboxWidget
.
Require any field. Validation is included.
For information on requiring fields or components, see "About the schema and uiSchema objects."
This indicates to the user that they have either not filled out a required field or they have not done so within the form's parameters. You can set a custom error message to help the user progress with the form.
There are several ways that form fields can be invalid, such as a required field is blank, the entry is too short or long, or the entry does not satisfy a specific format.
- To show an error on a blank field that is required, include the field in the array under the
required
property in theschema
. An error on that field will automatically be rendered if the field is blank. - To show an error on a field for any other reason (e.g., it has not met certain data requirements), pass a validation function to the array for the
ui:validations
property under that field inuiSchema
.
The error message that is displayed can either be a default message or one that you specify. There are several default error messages for different situations.
To show a custom error message, add the message to the ui:errorMessages
object in the uiSchema
as a key value pair:
- The key is the
schema
property that the data is in violation of (e.g., the entry doesn't match the requirements of thepattern
property). - The value is the text of the error message.
When you include multiple messages in the ui:errorMessages
object, they will be evaluated in order.
Your config file may look like this:
schema: {
type: 'object',
required: ['ssn'],
properties: {
ssn: {
type: 'string',
pattern: '^[0-9]{9}$'
}
}
},
uiSchema: {
ssn: {
'ui:widget': SSNWidget,
'ui:title': 'Social Security number',
'ui:validations': [
validateSSN
],
'ui:errorMessages': {
required: 'Please enter your SSN',
pattern: 'Please enter a valid 9 digit SSN (dashes not allowed)'
}
}
}
This feature validates that a user has correctly entered duplicate data in two fields.
For more information, see "Validating a field based on other fields in the same object."
You can set follow up questions to appear only if the user answers a form question a particular way.
There are 2 fields you can use to conditionally expand a form field:
expandUnder
: This property takes the name of the other field upon which your field is shown.expandUnderCondition
: This property takes 1 of 2 values:- The answer to the other field that would satisfy the condition to show your field. If the other field takes boolean data, your field will automatically be shown if the answer to the other field is
true
, so there is no need to includeexpandUnderCondition: true
in that case. However, if the other field takes any other type of data, you will need to includeexpandUnderCondition
. - A function that receives the data from the
expandUnder
field as an argument.
Both fields are nested under the ui:options
property in the uiSchema
.
The expandUnder
and expandUnderCondition
properties are distinctly separate from the depends
property, which conditionally shows entire pages of the form. For more information, see "Conditionally excluding a page."
Your config file might look like this:
{
schema: {
type: 'object',
properties: {
hasPet: {
type: 'boolean'
},
petName: {
type: 'string'
}
}
},
uiSchema: {
hasPet: {
'ui:title': 'Do you have a pet?'
'ui:widget': 'yesNo'
},
petName: {
'ui:title': 'What is your pet‘s name?',
'ui:options': {
expandUnder: 'hasPet',
expandUnderCondition: true
}
}
}
}
For the code implementation, see helpers.js
.
Use this feature to collect multiple items with the same form questions, such as addresses in a time period, jobs in a time period, or employment in a time period.
To display multiple groups of the same form questions, define the data in the schema
as type: 'array'
, with each group of questions as an item
in that array
. The schema
and uiSchema
for the group of questions within the items
object is structured the same as other fields.
Your config file might look like this:
{
schema: {
type: 'object',
properties: {
dogs: {
type: 'array',
items: {
type: 'object',
properties: {
nameOfDog: { type: 'string' },
age: { type: 'string' },
breed: { type: 'string' }
}
}
}
}
},
uiSchema: {
'ui:title': 'How many dogs do you have?',
items: {
nameOfDog: { 'ui:title': 'What is your dog‘s name?' },
age: { 'ui:title': 'How old is your dog?' },
breed: { 'ui:title': 'What is your dog‘s breed?' }
}
}
}
When you build a form with more than one chapter (shown by the segments in a progress bar), the review page lets a user edit all of their entered form data without having to go back one page at a time.
The review page renders the form data in review mode automatically. However, you can pass some specific options to the form config to customize some review features.
This property is nested directly under uiSchema
:
'ui:reviewWidget'
: takes a widget component to render on the review page for that field. Default review widgets are automatically rendered, so only use this if you need to customize the review widget that is used.
These properties are nested under uiSchema: {
ui:options: {} }
:
hideOnReview
: Hides the field on the review page; takes aboolean
hideOnReviewIfFalse
: Hides the field on the review page when the field value isfalse
; takes aboolean
keepInPageOnReview
: By default, array fields that are displayed on a single page in a form, such as information for multiple dependents, are displayed in a separate section on the review page. To keep the information in a single section on a review page, set this property.
For the code implementation, see the review
folder.
Use this feature to require a user to agree they have read terms and conditions, a privacy policy, or any other text before submitting your form. It includes a checkbox and short-form text that can include relevant links to additional information on separate pages.
To configure this feature, place a preSubmitInfo
object in the formConfig
. These are the available options:
notice
: (Optional) A text string or React element placed above the checkbox and submit button. If the form definition file is.jsx
the definition can be inline, or useimport
to reference an external component. If not specified, no notice appears.required
: (Optional) Whentrue
, a checkbox and label appear above the submit button. The user must check the box before submitting the form. Whenfalse
or not specified, thefield
,label
, anderror
options are not used.field
: The name of the form field for the required checkbox. This field has the valuetrue
in the submitted form data.label
: A text string or React element that labels the checkbox.error
: A text string or React element displayed as an error message if the user attempts to submit the form without checking the checkbox.
This is an example of preSubmitInfo
:
preSubmitInfo: {
required: true,
field: 'privacyAgreementAccepted',
label: <span>I have read and accept the <a href="/privacy">privacy policy</a>.</span>,
error: 'You must accept the privacy policy before continuing',
}
If you don't specify a preSubmitInfo
section, no notice or checkbox appears above the submit button. Most applications will want to give some sort of notice to the user before they submit the form. Although this section is optional, we recommend you specify it.
For the code implementation, see PreSubmitSection
and SubmitController
.
If you provide a function for formConfig.recordEvent
, the library calls that function when notable events occur. If you do not provide a function, the library logs these events onto the browser console.
The recordEvent
function receives a single object that can contain different information depending on the kind of event being reported. Events reported by the library always have a event
property that is a string describing the event. The events currently supported by the library are:
- validation-failed-on-submit: This is likely an error in the form definition or a React component, since the form should be completely validated at this point.
- form-submit-pending: An informational message showing that the user has pressed the submit button, and that the form has validated and been sent to the server.
- form-submit-successful: The server returned a status indicating it has accepted the form.
- form-submit-error: The form was submitted, but the server didn't accept the submission. The object contains an
error
anderrorType
with more information about the nature of the error.
Other events may be added in the future. This recordEvent
logs events to Google Analytics, except for pending/successful form submits which are filtered out:
formConfig = {
...
// The Google Analytics code snippet loads in the main document
// https://developers.google.com/analytics/devguides/collection/analyticsjs/
recordEvent: data => {
// Don't log if GA is not (yet) loaded or if this is a form success/pending
if (!window.dataLayer || /^form-submit-(successful|pending)$/.test(data.event)) {
return;
}
return window.dataLayer.push(data);
},
...
};
Web applications can fail for many reasons, including bad Internet connections, outdated browsers, and misbehaved browser extensions. Even if you test thoroughly, users may experience frustrating errors that they do not or cannot report. We highly recommend that you use an error-reporting and/or event-reporting service to track the use of your forms. Examples of services that could be used are Google Analytics, Errorception, Sentry, Airbrake, and Raygun.