Form Components
Form Components
Section titled “Form Components”Purpose
Section titled “Purpose”Form components provide React Hook Form-integrated input wrappers with built-in validation, error display, and consistent styling across the application.
When to Use
Section titled “When to Use”- Building forms with validation (group creation, wishlist editing)
- Need automatic error handling and display
- Require controlled input components with React Hook Form
Public API
Section titled “Public API”RHFTextField
Section titled “RHFTextField”Text input with label and error message.
interface RHFTextFieldProps { name: string; // Form field name (required) label?: string; // Input label placeholder?: string; // Placeholder text type?: 'text' | 'email' | 'url' | 'number' | 'password'; multiline?: boolean; // Textarea mode rows?: number; // Rows for multiline disabled?: boolean; helperText?: string; // Additional hint text}RHFSelect
Section titled “RHFSelect”Dropdown select input.
interface RHFSelectProps { name: string; label?: string; options: Array<{ value: string | number; label: string }>; disabled?: boolean;}RHFCheckbox
Section titled “RHFCheckbox”Checkbox with label.
interface RHFCheckboxProps { name: string; label: string; disabled?: boolean;}RHFDatePicker
Section titled “RHFDatePicker”Date picker using MUI DatePicker.
interface RHFDatePickerProps { name: string; label?: string; minDate?: Date; maxDate?: Date; disabled?: boolean;}RHFUpload
Section titled “RHFUpload”File upload with preview.
interface RHFUploadProps { name: string; accept?: string; // e.g., 'image/*' maxSize?: number; // Max file size in bytes onDrop?: (files: File[]) => void;}Basic Form Example
Section titled “Basic Form Example”import { useForm } from 'react-hook-form';import { yupResolver } from '@hookform/resolvers/yup';import * as yup from 'yup';import { RHFTextField, RHFDatePicker, RHFCheckbox } from 'src/components/hook-form';
const schema = yup.object({ name: yup.string().required('Name is required'), email: yup.string().email('Invalid email').required('Email is required'), date: yup.date().min(new Date(), 'Date must be in future').required(), agree: yup.boolean().oneOf([true], 'You must agree'),});
function MyForm() { const { control, handleSubmit, formState: { errors } } = useForm({ resolver: yupResolver(schema), defaultValues: { name: '', email: '', date: null, agree: false, }, });
const onSubmit = async (data) => { console.log(data); };
return ( <form onSubmit={handleSubmit(onSubmit)}> <RHFTextField name="name" label="Name" control={control} /> <RHFTextField name="email" label="Email" type="email" control={control} /> <RHFDatePicker name="date" label="Event Date" control={control} /> <RHFCheckbox name="agree" label="I agree to terms" control={control} /> <button type="submit">Submit</button> </form> );}With Custom Validation
Section titled “With Custom Validation”<RHFTextField name="budget" label="Budget" type="number" control={control} rules={{ required: 'Budget is required', min: { value: 1, message: 'Must be at least $1' }, max: { value: 1000, message: 'Must be under $1000' }, }}/>Behavior and Constraints
Section titled “Behavior and Constraints”- Automatic error display: Errors from
formState.errorsshown below input - Material-UI styling: Uses MUI TextField with theme integration
- Accessibility: Proper labels, aria-attributes, and error associations
- Validation timing: On blur and submit by default
Testing
Section titled “Testing”import { render, screen } from '@testing-library/react';import userEvent from '@testing-library/user-event';
it('should display error on invalid input', async () => { render(<MyForm />);
const input = screen.getByLabelText(/email/i); await userEvent.type(input, 'invalid-email'); await userEvent.tab(); // Trigger blur
expect(screen.getByText(/invalid email/i)).toBeInTheDocument();});Further Reading
Section titled “Further Reading”- Secret Santa Groups - Group creation form
- Item Management - Item creation form