Skip to main content

Form Components

Overview

The Form Components library provides a comprehensive set of form input components built on top of Chakra UI and React Hook Form. These components follow consistent patterns for validation, error handling, and accessibility, making form development more efficient and maintainable.

Component Categories

Input Components

  • WPInput - Standard text input with validation
  • WPTextField - Textarea component for multi-line text
  • WPNumberInput - Numeric input with validation
  • FormField - Generic form field wrapper
  • WPPinInput - PIN code input component

Select Components

  • WPSelect - Single/multi-select dropdown
  • WPCreatableSelect - Select with ability to create new options

Date/Time Components

  • WPDatepicker - Date picker with calendar interface
  • WPTimePicker - Time selection component

Form Layout Components

  • WPForm - Main form container
  • WPFormHStack - Horizontal form layout
  • WPFormStack - Vertical form layout
  • FormLayout - Advanced form layout utilities

Advanced Components

  • WPPasswordValidator - Password input with validation rules
  • WPPhoneInput - International phone number input
  • ActionModal - Modal component for form actions
  • ExportModal - Specialized modal for data export forms

Architecture

Version Support

The library supports multiple versions of React Hook Form:

  • V7 Components (/V7/) - Latest React Hook Form (v7+)
  • V2 Components (/V2/) - Legacy React Hook Form (v6)
  • Legacy Components - Original implementations

Hook Form Integration

All components are designed to work seamlessly with React Hook Form:

import { useForm } from 'react-hook-form';
import { WPInput } from 'components/Forms/WPInput';

function MyForm() {
const {
register,
handleSubmit,
control,
formState: { errors },
} = useForm();

return (
<form onSubmit={handleSubmit(onSubmit)}>
<WPInput
name='username'
label='Username'
register={register}
error={errors.username}
isRequired
/>
</form>
);
}

When to Use

WPInput

  • Use for standard text inputs (name, email, etc.)
  • When you need validation and error handling
  • For controlled form inputs with React Hook Form

WPTextField

  • Use for multi-line text input (comments, descriptions)
  • When you need resizable text areas
  • For longer content input

WPSelect

  • Use for dropdown selections
  • When you need multi-select functionality
  • For searchable select options

WPDatepicker

  • Use for date selection
  • When you need date range selection
  • For calendar-based date input

FormLayout Components

  • Use WPForm as the main form container
  • Use WPFormHStack for horizontal form layouts
  • Use WPFormStack for vertical form layouts

Common Props

Standard Form Props

All form components share these common props:

PropTypeRequiredDefaultDescription
namestring-Form field name
labelstring--Field label
placeholderstring--Input placeholder text
isRequiredboolean-falseWhether field is required
isDisabledboolean-falseWhether field is disabled
errorFieldError--Error object from React Hook Form
helperTextstring--Helper text below input

React Hook Form Props

PropTypeRequiredDescription
registerFunctionReact Hook Form register function
controlControlReact Hook Form control object
rulesObject-Validation rules

API Documentation

WPInput

Props

PropTypeRequiredDefaultDescription
namestring-Input name
labelstring--Input label
placeholderstring--Placeholder text
type'text' | 'password' | 'number'-'text'Input type
registerFunction-React Hook Form register
errorFieldError--Error object
isRequiredboolean-falseRequired field
inputModestring-'text'Input mode
LeftElementReactNode--Left input addon
RightElementReactNode--Right input addon
formLabelStylestring--Label style
formLabelSizestring--Label size
helperTextstring--Helper text

Usage Example

import { WPInput } from 'components/Forms/WPInput';

<WPInput
name='email'
label='Email Address'
placeholder='Enter your email'
type='email'
register={register}
error={errors.email}
isRequired
helperText="We'll never share your email"
/>;

WPTextField

Props

PropTypeRequiredDefaultDescription
namestring-Textarea name
labelstring--Textarea label
placeholderstring--Placeholder text
registerFunction-React Hook Form register
errorFieldError--Error object
isRequiredboolean-falseRequired field
rowsnumber-3Number of rows
resizestring-'vertical'Resize behavior

Usage Example

import { WPTextField } from 'components/Forms/WPTextField';

<WPTextField
name='description'
label='Description'
placeholder='Enter description'
register={register}
error={errors.description}
rows={5}
/>;

WPSelect

Props

PropTypeRequiredDefaultDescription
namestring-Select name
labelstring--Select label
optionsArray-Select options
controlControl-React Hook Form control
placeholderstring--Placeholder text
isMultiboolean-falseEnable multi-select
isSearchableboolean-trueEnable search
isLoadingboolean-falseLoading state
isDisabledboolean-falseDisabled state
rulesObject--Validation rules

Usage Example

import { WPSelect } from 'components/Forms/WPSelect';

const options = [
{ value: 'option1', label: 'Option 1' },
{ value: 'option2', label: 'Option 2' },
];

<WPSelect
name='category'
label='Category'
options={options}
control={control}
placeholder='Select category'
isRequired
rules={{ required: 'Please select a category' }}
/>;

WPDatepicker

Props

PropTypeRequiredDefaultDescription
namestring-Date picker name
labelstring--Date picker label
controlControl-React Hook Form control
placeholderstring--Placeholder text
isRequiredboolean-falseRequired field
isClearableboolean-falseAllow clearing
withPortalboolean-falseRender in portal
showTimeSelectboolean-falseEnable time selection
dateFormatstring-'MM/dd/yyyy'Date format
rulesObject--Validation rules

Usage Example

import { WPDatepicker } from 'components/Forms/WPDatepicker';

<WPDatepicker
name='birthDate'
label='Birth Date'
control={control}
placeholder='Select date'
isClearable
rules={{ required: 'Please select a date' }}
/>;

FormLayout Components

WPForm

Main form container with consistent styling and spacing.

import { WPForm } from 'components/Forms/FormLayout';

<WPForm onSubmit={handleSubmit(onSubmit)}>{/* Form fields */}</WPForm>;

WPFormHStack

Horizontal form layout for side-by-side inputs.

import { WPFormHStack } from 'components/Forms/FormLayout';

&lt;WPFormHStack&gt;
<WPInput name='firstName' label='First Name' />
<WPInput name='lastName' label='Last Name' />
</WPFormHStack>;

WPFormStack

Vertical form layout for stacked inputs.

import { WPFormStack } from 'components/Forms/FormLayout';

&lt;WPFormStack&gt;
<WPInput name='email' label='Email' />
<WPInput name='password' label='Password' />
</WPFormStack>;

Advanced Components

WPPasswordValidator

Password input with built-in validation rules and strength indicator.

import { WPPasswordValidator } from 'components/Forms/WPPasswordValidator';

<WPPasswordValidator
name='password'
label='Password'
control={control}
rules={{
required: 'Password is required',
minLength: {
value: 8,
message: 'Password must be at least 8 characters',
},
}}
/>;

WPPhoneInput

International phone number input with country selection.

import { WPPhoneInput } from 'components/Forms/WP-PhoneInput';

<WPPhoneInput
name='phone'
label='Phone Number'
control={control}
defaultCountry='US'
placeholder='Enter phone number'
/>;

ActionModal

Modal component for form actions with consistent styling.

import ActionModal from 'components/Forms/Modals/ActionModal';

<ActionModal
isOpen={isOpen}
onClose={onClose}
heading='Edit Profile'
footer={<Button onClick={handleSubmit}>Save Changes</Button>}
>
&lt;WPForm&gt;{/* Form fields */}</WPForm>
</ActionModal>;

Form Patterns

Basic Form with Validation

import { useForm } from 'react-hook-form';
import { WPForm, WPInput, WPSelect, WPDatepicker } from 'components/Forms';

function UserForm() {
const {
register,
handleSubmit,
control,
formState: { errors },
} = useForm();

const onSubmit = data => {
console.log(data);
};

return (
<WPForm onSubmit={handleSubmit(onSubmit)}>
<WPInput
name='name'
label='Full Name'
register={register}
error={errors.name}
isRequired
/>

<WPSelect
name='role'
label='Role'
options={roleOptions}
control={control}
rules={{ required: 'Please select a role' }}
/>

<WPDatepicker
name='startDate'
label='Start Date'
control={control}
rules={{ required: 'Please select a start date' }}
/>

<Button type='submit'>Submit</Button>
</WPForm>
);
}

Form with Custom Validation

function CustomValidationForm() {
const {
register,
handleSubmit,
control,
formState: { errors },
watch,
} = useForm();

const password = watch('password');

return (
<WPForm onSubmit={handleSubmit(onSubmit)}>
<WPInput
name='email'
label='Email'
register={register}
error={errors.email}
rules={{
required: 'Email is required',
pattern: {
value: /\S+@\S+\.\S+/,
message: 'Invalid email format',
},
}}
/>

<WPInput
name='password'
label='Password'
type='password'
register={register}
error={errors.password}
rules={{
required: 'Password is required',
minLength: {
value: 8,
message: 'Password must be at least 8 characters',
},
}}
/>

<WPInput
name='confirmPassword'
label='Confirm Password'
type='password'
register={register}
error={errors.confirmPassword}
rules={{
required: 'Please confirm your password',
validate: value => value === password || 'Passwords do not match',
}}
/>
</WPForm>
);
}

Multi-step Form

function MultiStepForm() {
const [step, setStep] = useState(1);
const methods = useForm();

const nextStep = () => setStep(step + 1);
const prevStep = () => setStep(step - 1);

return (
<FormProvider {...methods}>
&lt;WPForm&gt;
{step === 1 && <Step1 onNext={nextStep} />}
{step === 2 && <Step2 onNext={nextStep} onPrev={prevStep} />}
{step === 3 && <Step3 onPrev={prevStep} />}
</WPForm>
</FormProvider>
);
}

Styling & Theming

Theme Integration

Form components use Chakra UI's theming system:

// Custom theme for form components
const formTheme = {
components: {
FormLabel: {
baseStyle: {
color: 'charcoal',
fontSize: 'sm',
fontWeight: 'medium',
},
},
Input: {
baseStyle: {
field: {
borderColor: 'gray.300',
_focus: {
borderColor: 'green.500',
},
},
},
},
},
};

Custom Styling

<WPInput
name='customField'
label='Custom Field'
register={register}
formLabelStyle='text-caps'
formLabelSize='lg'
sx={{
'& .chakra-input': {
borderRadius: 'md',
borderColor: 'blue.300',
},
}}
/>

Accessibility

ARIA Support

  • All form components include proper ARIA labels
  • Error messages are associated with inputs
  • Required fields are properly marked
  • Form validation provides screen reader feedback

Keyboard Navigation

  • Tab navigation between form fields
  • Enter key submits forms
  • Escape key clears inputs (when applicable)
  • Arrow keys navigate select options

Error Handling

  • Error messages are announced to screen readers
  • Invalid fields are marked with aria-invalid
  • Error icons provide visual feedback
  • Form validation prevents submission of invalid data

Migration Guide

From V6 to V7 React Hook Form

// V6 (Legacy)
import { WPInput } from 'components/Forms/WPInput';

<WPInput name='field' register={register} error={errors.field} />;

// V7 (Current)
import { WPInput } from 'components/Forms/V7/WPInput';

<WPInput
name='field'
control={control}
rules={{ required: 'Field is required' }}
/>;

Component Updates

  • Replace register prop with control
  • Move validation to rules prop
  • Update error handling patterns
  • Use useController for custom components

Best Practices

  1. Consistent Validation: Use common validation rules across forms
  2. Error Handling: Provide clear, actionable error messages
  3. Loading States: Show loading indicators during form submission
  4. Accessibility: Test with screen readers and keyboard navigation
  5. Performance: Use React.memo for expensive form components
  6. Type Safety: Use TypeScript interfaces for form data

Testing

Unit Testing

import { render, screen } from '@testing-library/react';
import { useForm } from 'react-hook-form';
import { WPInput } from 'components/Forms/WPInput';

function TestForm() {
const {
register,
formState: { errors },
} = useForm();

return (
<WPInput
name='test'
label='Test Input'
register={register}
error={errors.test}
/>
);
}

test('renders input with label', () => {
render(<TestForm />);
expect(screen.getByLabelText('Test Input')).toBeInTheDocument();
});

Integration Testing

import { render, screen, fireEvent } from '@testing-library/react';
import userEvent from '@testing-library/user-event';

test('form submission with validation', async () => {
const user = userEvent.setup();
const onSubmit = jest.fn();

render(<MyForm onSubmit={onSubmit} />);

// Fill form
await user.type(screen.getByLabelText('Email'), 'test@example.com');
await user.click(screen.getByRole('button', { name: 'Submit' }));

expect(onSubmit).toHaveBeenCalledWith({
email: 'test@example.com',
});
});

Common Issues

Form Not Submitting

  • Check that all required fields are filled
  • Verify validation rules are correct
  • Ensure form is wrapped in <form> tag
  • Check for JavaScript errors in console

Validation Not Working

  • Ensure rules prop is properly configured
  • Check React Hook Form version compatibility
  • Verify control object is passed correctly
  • Test validation rules independently

Styling Issues

  • Check Chakra UI theme configuration
  • Verify CSS-in-JS styles are applied
  • Test responsive behavior
  • Check for style conflicts

Performance Optimization

Lazy Loading

const WPDatepicker = lazy(() => import('components/Forms/WPDatepicker'));

<Suspense fallback={<Spinner />}>
<WPDatepicker name='date' control={control} />
</Suspense>;

Memoization

const MemoizedWPInput = memo(WPInput);

// Use in forms with many fields
<MemoizedWPInput name='field' register={register} error={errors.field} />;

Debounced Validation

const debouncedValidation = useMemo(() => debounce(validateField, 300), []);

<WPInput name='field' register={register} onChange={debouncedValidation} />;