Skip to Content
ContentCore Concepts

Core Concepts

Understanding the mental models and architecture of Hero Hook Form.

Architecture Overview

Hero Hook Form is built on three core pillars:

  1. React Hook Form - Form state management and validation
  2. HeroUI Components - Beautiful, accessible UI components
  3. TypeScript - Type safety and developer experience
ℹ️ Info

Key Principle: Hero Hook Form wraps React Hook Form and HeroUI to provide a type-safe, accessible form building experience with minimal boilerplate.

Form Lifecycle

Forms go through four main stages:

1. Initialization

The form is created with schema and field configuration:

const form = useForm({ resolver: zodResolver(schema), defaultValues: { name: "", email: "" } });

2. Rendering

Fields are rendered based on configuration:

<FormField config={fieldConfig} form={form} />

3. Validation

Validation happens on blur, change, or submit:

const isValid = await form.trigger();

4. Submission

Form data is validated and submitted:

const handleSubmit = (data) => { // Process validated data };
💡 Tip

Validation can be triggered automatically (onBlur, onChange) or manually using form.trigger().

Data Model

Form Configuration

interface FormConfig<T> { fields: FormFieldConfig<T>[]; layout?: "vertical" | "horizontal" | "grid"; defaultValues?: Partial<T>; }

Field Configuration

interface FormFieldConfig<T> { name: Path<T>; type: "input" | "textarea" | "select" | "checkbox" | "switch" | "radio"; label?: string; description?: string; // ... type-specific props }

Form State

interface FormState { isSubmitting: boolean; isSubmitted: boolean; isSuccess: boolean; errors: FieldErrors<T>; values: T; }

Field Types

Text Fields

  • Input - Single-line text input
  • Textarea - Multi-line text input
  • Select - Dropdown selection

Boolean Fields

  • Checkbox - Checkbox input
  • Switch - Toggle switch

Choice Fields

  • Radio - Radio button group
  • Select - Dropdown selection

Specialized Fields

  • Date - Date picker
  • File - File upload
  • Slider - Numeric slider
  • FontPicker - Font selection

Dynamic Fields

  • Conditional - Show/hide based on form data
  • FieldArray - Dynamic repeating fields
  • DynamicSection - Grouped conditional fields

Content Fields

  • Content - Headers, questions, or custom content between fields

Validation Patterns

Schema-First Validation

const schema = z.object({ email: z.string().email(), password: z.string().min(8), });

Cross-Field Validation

const schema = z.object({ password: z.string(), confirmPassword: z.string(), }).refine(data => data.password === data.confirmPassword, { message: "Passwords don't match", path: ["confirmPassword"], });

Conditional Validation

const schema = z.object({ hasPhone: z.boolean(), phone: z.string().optional(), }).refine(data => !data.hasPhone || data.phone, { message: "Phone is required", path: ["phone"], });

Performance Considerations

Memoization

All field components are wrapped with React.memo to prevent unnecessary re-renders.

💡 Tip

Field components automatically memoize, so you don’t need to wrap them yourself.

Debounced Validation

Use useDebouncedValidation for expensive validation operations:

import { useDebouncedValidation } from "@rachelallyson/hero-hook-form"; const { debouncedTrigger, isDebouncing } = useDebouncedValidation( form, { delay: 300 } );
⚠️ Warning

Without debouncing, validation runs on every keystroke, which can be expensive for complex validation logic.

Error Handling

Client-Side Errors

  • Field-level validation errors
  • Form-level validation errors
  • Custom validation rules

Server-Side Errors

import { applyServerErrors } from "@rachelallyson/hero-hook-form"; // Apply server errors to form applyServerErrors(form, { field1: "Server error message", field2: "Another error", });

Error Display

  • Inline field errors
  • Toast notifications
  • Modal error dialogs
  • Custom error components

Accessibility

ARIA Attributes

All form fields include proper ARIA attributes:

  • aria-label for field labels
  • aria-describedby for field descriptions
  • aria-invalid for validation state
  • aria-required for required fields

Keyboard Navigation

  • Tab order follows logical form flow
  • Enter key submits forms
  • Escape key cancels forms
  • Arrow keys navigate radio groups

Screen Reader Support

  • Field labels are properly associated
  • Error messages are announced
  • Form state changes are communicated
  • Loading states are indicated

Testing

Form Test Utilities

import { createFormTestUtils } from "@rachelallyson/hero-hook-form"; const testUtils = createFormTestUtils(form); await testUtils.submitForm(); const fieldValue = testUtils.getField("fieldName");

Cypress Integration

import { simulateFormSubmission } from "@rachelallyson/hero-hook-form/cypress"; cy.get('[data-testid="form"]').then(simulateFormSubmission);

Best Practices

Form Design

  1. Use clear, descriptive labels - Help users understand what each field is for
  2. Group related fields together - Use sections or visual grouping
  3. Provide helpful descriptions - Add context with field descriptions
  4. Show validation errors immediately - Use mode: "onBlur" or mode: "onChange"
  5. Use appropriate input types - email, tel, password, etc.

Performance

  1. Field components are already memoized - No need to wrap them
  2. Debounce expensive validations - Use useDebouncedValidation hook
  3. Use conditional fields - Only render what’s needed
  4. Avoid unnecessary re-renders - Let React Hook Form handle state
💡 Tip

For large forms, consider using conditional fields to only render visible sections.

Accessibility

  1. Always provide labels - Required for screen readers
  2. Use semantic HTML - HeroUI components handle this automatically
  3. Ensure keyboard navigation - Tab order follows form flow
  4. Test with screen readers - Verify ARIA attributes work correctly
  5. Provide error feedback - Errors are announced to screen readers
ℹ️ Info

Hero Hook Form components include proper ARIA attributes by default, but you should always provide labels.

Type Safety

  1. Define proper TypeScript interfaces - Or use Zod schema inference
  2. Use Zod schemas for validation - Single source of truth for types and validation
  3. Leverage type inference - Let TypeScript infer types from schemas
  4. Avoid any types - Use proper generics
  5. Use proper generic constraints - Ensure type safety throughout
⚠️ Warning

Field names must match your form data type. Use Path<T> types for nested fields.

Last updated on