How to use web component patterns
This guide explains how to use and adopt web component patterns for your VA form application.
Practically for developers, these patterns are the imports such as fullNameUI()
and fullNameSchema
to inject into an RJSF form’s uiSchema
and schema
(specifically from platform/forms-system/src/js/web-component-patterns
)
In order to be compliant with the design system and USWDS, all forms should adopt the use of web components, and using patterns allow us to do that in an easy way.
Terminology
Web component - Web components are a type of component created by the VA.gov Design System. They are interactive and non-interactive UI elements that can be grouped together or presented individually. They are independent, reusable chunks of a user interface. More information can be found here.
Pattern - As defined by the VADS, patterns incorporate one or more page layouts and components to create an interaction that can span multiple pages, a short or long time span, and potentially even multiple channels. More information can be found here.
Forms library web component field - An implementation of a VADS web component that enables its use in a digitized form. When the VADS updates a web component, the forms library version is also automatically updated. Note: it is recommended to use forms library web component patterns when possible as they leverage standardized validation, labels, form data, etc.
Forms library web component pattern - An implementation of a VADS pattern that utilizes one or more forms library web component field(s) that enables its use in a digitized form. They feature standardized validation, labels, fields, and more and include an importable
uiSchema
andschema
Forms library widget - The original method of rendering a field in react-jsonschema-form (what the forms library is forked from) that utilizes native React elements and USWDS stylings. These have been deprecated in favor of the web component fields due to multiple factors including maintainability, reusability, and accessibility factors
Before you start - JSONSchema warning ⚠️
RJSF VA Forms have traditionally been built by starting with a large JSONSchema representation of the data, but we intend to move away from this approach with web component patterns.
Web component patterns include a uiSchema AND a schema. The patterns own their own JSONSchema so that they can be reused and swapped easily.
See in action
You can see examples of patterns here https://staging.va.gov/mock-form-patterns/introduction
Step-by-step guide for creating a new form with patterns
Step 1: Prepare an RJSF page for uiSchema and schema (nothing new here)
import {} from 'platform/forms-system/src/js/web-component-patterns';
/** @type {PageSchema} */
export default {
uiSchema: {},
schema: {
type: 'object',
properties: {},
},
};
Tip: Using
/** @type {PageSchema} */
should help with intellisense (autocomplete).
Step 2: Find and use the patterns you need from platform/forms-system/src/js/web-component-patterns
They usually come in pairs like this:
// uiSchema
veteransFullName: fullNameUI()
// schema
veteransFullName: fullNameSchema
The patterns can represent a group of fields like in the case of full name, or sometimes single fields such as:
// uiSchema
hasHealthInsurance: yesNoUI({
title: 'Do you have health insurance coverage?'
labels: {
Y: 'Yes, I have health insurance',
N: 'No, I do not have health insurance',
},
})
// schema
hasHealthInsurance: yesNoSchema
Here is an example using three different patterns, title
, fullName
, and dateOfBirth
import {
fullNameSchema,
fullNameUI,
dateOfBirthSchema,
dateOfBirthUI,
titleSchema,
titleUI,
} from 'platform/forms-system/src/js/web-component-patterns';
/** @type {PageSchema} */
export default {
uiSchema: {
'view:title': titleUI('Name and date of birth'),
fullName: fullNameUI(),
dateOfBirth: dateOfBirthUI(),
},
schema: {
type: 'object',
properties: {
'view:title': titleSchema,
fullName: fullNameSchema,
dateOfBirth: dateOfBirthSchema,
},
},
};
Note that ‘view:something'
is recommended syntax for view only fields, so it won’t be confused with user data in redux or the POST call.
Step 3a: Simple Customization
Most patterns allow customizing the title with a simple string like this:
emailUI(“Veteran’s email address”)
or an object of custom options:
emailUI({
title: “Veteran’s email address”,
description: "A nice description",
hint: "This is a gray hint below the label"
})
But since the fullName pattern is a group of fields, if you hover fullNameUI, you’ll see that it accepts a function to format the title instead.
fullNameUI(title => `Veteran's {title}`)
Note that it’s preferred to use the person’s name in the page title rather than in the fields however (as you can see if you hover over fullNameUI)
Step 3b: Use variants if default pattern does not work
if you hover fullNameSchema, you’ll see that is an object consistenting of firstName
, middleName
, lastName
, and suffix
.
If you instead want a variant of this, check web-component-patterns/fullNamePatterns.js
.
fullNameNoSuffixUI,
fullNameWithMaidenNameUI,
fullNameUI,
fullNameSchema,
fullNameNoSuffixSchema,
fullNameWithMaidenNameSchema,
Step 3c: Customization for unsupported properties
If needed, you may have to simply destructure a pattern in order to add your customization. However maybe it makes sense instead to enhance or create a new pattern, which is Step 4.
Step 4: Contributing patterns, variations, or new options to an existing pattern.
You might find a need for a pattern or a customization that is missing. In that case, please do consider contributing to the web-component-patterns
. However, here are some guidelines:
Consult with UX and DST before creating a new pattern to make sure this is something that we think is common and should be a ‘standard’.
Prefer standardization over high customizability, and limit customization to only what is necessary
Prefer to create a new specific pattern vs a bunch of props into a pattern to customize it however you like. This will encourage reusability of specific known patterns.
Do not pass props like this (prop1, prop2, prop3, prop4) into a pattern. A simple string, or an object is preferred for props.
Step-by-step guide for updating existing forms with patterns (WIP)
Step 1: Update existing patterns to the web component version
Here are some example replacements of common patterns:
This example mock form has side by side examples of regular WJSF vs its web component version:
Old:
import currentOrPastDateUI from 'platform/forms-system/src/js/definitions/currentOrPastDate';
// uiSchema
dateCustom: currentOrPastDateUI('Custom date')
// schema
dateCustom: // from JSONSchema
New:
import {
currentOrPastDateUI
currentOrPastDateSchema
} from 'platform/forms-system/src/js/web-component-patterns';
// uiSchema
dateCustom: currentOrPastDateUI('Custom date')
// schema
dateCustom: currentOrPastDateSchema
Before:
discloseFinancialInformation: {
'ui:title': 'Do you want to provide your financial information?',
'ui:widget': 'yesNo',
}
After:
// uiSchema
discloseFinancialInformation: yesNoUI('Do you want to provide your financial information?')
// schema
discloseFinancialInformation: yesNoSchema
See https://github.com/department-of-veterans-affairs/vets-website/tree/main/src/platform/forms-system/src/js/web-component-patterns for all available patterns.
Step 2: For anything that is not a pattern, add 'ui:webComponentField'
to an existing RJSF field
To most existing RJSF code, you can add this property to make it into a web component:
Before:
simpleText: {
'ui:title': 'TextWidget - with string description',
'ui:description': 'Text description',
},
After:
import VaTextInputField from 'platform/forms-system/src/js/web-component-fields/VaTextInputField';
simpleText: {
'ui:title': 'TextWidget - with string description',
'ui:description': 'Text description',
'ui:webComponentField': VaTextInputField
}
Before:
selectCustom: {
'ui:title': 'Custom select',
'ui:description': 'description',
'ui:options': {
labels: {
option1: 'Option 1',
option2: 'Option 2',
},
},
},
After:
import VaSelectField from 'platform/forms-system/src/js/web-component-fields/VaSelectField';
selectCustom: {
'ui:title': 'Custom select',
'ui:webComponentField': VaSelectField,
'ui:description': 'description',
'ui:options': {
labels: {
option1: 'Option 1',
option2: 'Option 2',
},
},
}
See https://github.com/department-of-veterans-affairs/vets-website/tree/main/src/platform/forms-system/src/js/web-component-fields for all existing field mappings
Create or update a pattern
If you have a new pattern, or an update to an existing pattern that involves new fields or components, consider contributing back to the design system. Reach out to the design system team if you have any questions. Create or update a pattern
For existing patterns, label, hint text, or validation changes are encouraged to meet form requirements and do not count as a customization or deviation
Help and feedback
Get help from the Platform Support Team in Slack.
Submit a feature idea to the Platform.