Skip to Content
DocumentationPackages@formkit-gov/react

@formkit-gov/react

React components wrapping VA Design System with React Hook Form integration.

Installation

npm install @formkit-gov/react react react-dom react-hook-form zod @hookform/resolvers @department-of-veterans-affairs/component-library

Features

  • VA Design System web component wrappers
  • React Hook Form integration
  • Accessible form controls (WCAG 2.1 AA)
  • shadcn/ui-style composable form pattern
  • Full TypeScript support

Form Components

Core form components following the shadcn/ui composable pattern:

ComponentDescription
FormForm wrapper with React Hook Form context
FormFieldField wrapper with React Hook Form binding
FormItemForm item container
FormControlControl wrapper for form inputs
FormLabelAccessible label component
FormDescriptionField description/hint text
FormMessageError message display

Basic Form Example

import { useForm } from 'react-hook-form'; import { zodResolver } from '@hookform/resolvers/zod'; import { z } from 'zod'; import { Form, FormField, FormItem, FormLabel, FormControl, FormMessage, TextInputField, } from '@formkit-gov/react'; const schema = z.object({ firstName: z.string().min(1, 'First name is required'), email: z.string().email('Enter a valid email address'), }); type FormData = z.infer<typeof schema>; function MyForm() { const form = useForm<FormData>({ resolver: zodResolver(schema), defaultValues: { firstName: '', email: '' }, }); return ( <Form form={form} onSubmit={data => console.log(data)}> <FormField control={form.control} name="firstName" render={({ field }) => ( <FormItem> <FormLabel>First name</FormLabel> <FormControl> <TextInputField {...field} /> </FormControl> <FormMessage /> </FormItem> )} /> <FormField control={form.control} name="email" render={({ field }) => ( <FormItem> <FormLabel>Email</FormLabel> <FormControl> <TextInputField type="email" {...field} /> </FormControl> <FormMessage /> </FormItem> )} /> <button type="submit">Submit</button> </Form> ); }

Field Components

VA Design System web component wrappers with consistent APIs.

ComponentDescription
TextInputFieldSingle-line text input
TextareaFieldMulti-line text input
NumberFieldNumeric input with validation
CurrencyFieldCurrency input with formatting
PhoneFieldPhone number input with formatting
SSNFieldSocial Security Number input (masked)
DateFieldDate picker input
MemorableDateFieldSeparate month/day/year inputs
SelectFieldDropdown select
ComboBoxFieldSearchable dropdown with autocomplete
CheckboxFieldSingle checkbox
CheckboxGroupFieldGroup of checkboxes
RadioFieldRadio button group
FileUploadFieldFile upload with validation
PrivacyAgreementFieldPrivacy agreement checkbox

Using Field Components Directly

Field components can be used standalone without React Hook Form:

import { useState } from 'react'; import { TextInputField, SelectField, CheckboxField } from '@formkit-gov/react'; function StandaloneFields() { const [firstName, setFirstName] = useState(''); const [state, setState] = useState(''); const [agreed, setAgreed] = useState(false); return ( <div> <TextInputField label="First name" value={firstName} onChange={e => setFirstName(e.target.value)} error={firstName ? undefined : 'This field is required'} required /> <SelectField label="State" value={state} onChange={e => setState(e.target.value)} options={[ { value: 'CA', label: 'California' }, { value: 'TX', label: 'Texas' }, ]} /> <CheckboxField label="I agree to the terms" checked={agreed} onChange={e => setAgreed(e.target.checked)} /> </div> ); }

Molecular Components

Pre-composed field groups for common patterns.

ComponentDescription
FullNameFieldFirst name, middle name, last name, and suffix
AddressFieldComplete address with street, city, state, zip

Full Name Field

import { useState } from 'react'; import { FullNameField } from '@formkit-gov/react'; function NameForm() { const [name, setName] = useState({ first: '', middle: '', last: '', suffix: '' }); return ( <FullNameField value={name} onChange={setName} config={{ middle: { show: true }, suffix: { show: true }, }} /> ); }

Address Field

import { useState } from 'react'; import { AddressField } from '@formkit-gov/react'; function AddressForm() { const [address, setAddress] = useState({ street: '', street2: '', city: '', state: '', zipCode: '', }); return <AddressField value={address} onChange={setAddress} />; }

Review Components

Components for displaying form data before submission.

ComponentDescription
ReviewSectionSection container with edit link
ReviewItemSingle label/value display
ReviewListList of review items

Review Page Example

import { ReviewSection, ReviewItem, ReviewList } from '@formkit-gov/react'; function ReviewPage({ onEditStep }: { onEditStep: (step: number) => void }) { return ( <div> <ReviewSection title="Personal Information" onEdit={() => onEditStep(1)}> <ReviewItem label="Name" value="John Doe" /> <ReviewItem label="Email" value="john@example.com" /> </ReviewSection> <ReviewSection title="Address" onEdit={() => onEditStep(2)}> <ReviewList items={[ { label: 'Street', value: '123 Main St' }, { label: 'City', value: 'San Francisco' }, { label: 'State', value: 'CA' }, ]} /> </ReviewSection> </div> ); }

Field Layout Primitives

Low-level layout components for custom field arrangements.

ComponentDescription
FieldBase field container
FieldGroupGroup of related fields
FieldSetFieldset with legend
FieldLegendLegend for fieldset
FieldLabelLabel element
FieldContentContent wrapper
FieldTitleTitle text
FieldDescriptionDescription/hint text
FieldErrorError message
FieldSeparatorVisual separator

Integration with @formkit-gov/core

Combine React components with core schemas for full validation:

import { useForm } from 'react-hook-form'; import { zodResolver } from '@hookform/resolvers/zod'; import { z } from 'zod'; import { Form, FormField } from '@formkit-gov/react'; import { TextInputField, PhoneField } from '@formkit-gov/react/components'; import { createTextSchema, createPhoneSchema } from '@formkit-gov/core/schemas'; const schema = z.object({ name: createTextSchema({ required: true, maxLength: 100 }), phone: createPhoneSchema(), }); function ContactForm() { const form = useForm({ resolver: zodResolver(schema), defaultValues: { name: '', phone: '' }, }); return ( <Form form={form} onSubmit={data => console.log(data)}> <FormField control={form.control} name="name" render={({ field, fieldState }) => ( <TextInputField {...field} label="Your name" error={fieldState.error?.message} required /> )} /> <FormField control={form.control} name="phone" render={({ field, fieldState }) => ( <PhoneField {...field} label="Phone number" error={fieldState.error?.message} /> )} /> <va-button type="submit">Submit</va-button> </Form> ); }

Accessibility

All components are built with accessibility in mind:

  • WCAG 2.1 AA compliant
  • Proper ARIA attributes
  • Keyboard navigation support
  • Screen reader compatible
  • Error messages associated with fields
  • Focus management

Interactive Examples

Visit Storybook  for interactive component demos with live code editing.

Next Steps

Last updated on