Skip to main content
Skip table of contents

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 and schema

  • 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)

CODE
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:

CODE
// 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:

CODE
// 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

CODE
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:

CODE
emailUI(“Veteran’s email address”)

or an object of custom options:

CODE
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.

CODE
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.

CODE
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:

CODE
import currentOrPastDateUI from 'platform/forms-system/src/js/definitions/currentOrPastDate';

// uiSchema
dateCustom: currentOrPastDateUI('Custom date')

// schema
dateCustom: // from JSONSchema

New:

CODE
import {
  currentOrPastDateUI
  currentOrPastDateSchema
} from 'platform/forms-system/src/js/web-component-patterns';

// uiSchema
dateCustom: currentOrPastDateUI('Custom date')

// schema
dateCustom: currentOrPastDateSchema

Before:

CODE
discloseFinancialInformation: {
      'ui:title': 'Do you want to provide your financial information?',
      'ui:widget': 'yesNo',
    }

After:

CODE
// 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:

CODE
simpleText: {
    'ui:title': 'TextWidget - with string description',
    'ui:description': 'Text description',
},

After:

CODE
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:

CODE
selectCustom: {
      'ui:title': 'Custom select',
      'ui:description': 'description',
      'ui:options': {
        labels: {
          option1: 'Option 1',
          option2: 'Option 2',
        },
      },
    },

After:

CODE
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


JavaScript errors detected

Please note, these errors can depend on your browser setup.

If this problem persists, please contact our support.