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
registerFunction✓React Hook Form register function
controlControl✓React 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} />;