Skip to Content
ContentGuidesQuickstart

Quick Start Guide

Get up and running with Hero Hook Form in 5 minutes.

đź’ˇ Tip

This guide will help you create your first form. For a detailed comparison of different form building patterns, see the Form Patterns Comparison guide.

Installation

Install Hero Hook Form and its peer dependencies:

npm install @rachelallyson/hero-hook-form zod @hookform/resolvers
ℹ️ Info

Peer Dependencies: Make sure you also have react, react-dom, react-hook-form, and @heroui/react installed. These are required peer dependencies.

Your First Form

Create a simple contact form in just a few lines:

import { ZodForm, FormFieldHelpers } from "@rachelallyson/hero-hook-form"; import { z } from "zod"; const schema = z.object({ email: z.string().email(), name: z.string().min(2), }); export default function ContactForm() { return ( <ZodForm config={{ schema, fields: [ FormFieldHelpers.input("name", "Name"), FormFieldHelpers.input("email", "Email", "email"), ], }} onSubmit={(data) => console.log(data)} /> ); }
📝 Note

Expected Result: Invalid inputs show error messages; valid submission logs typed data.

Optional: Wrap Your App

For global form defaults and styling, wrap your app with the provider:

import { HeroHookFormProvider } from "@rachelallyson/hero-hook-form"; export function App() { return ( <HeroHookFormProvider> <YourForms /> </HeroHookFormProvider> ); }
ℹ️ Info

The provider is optional but recommended for consistent styling and default configurations across all forms.

Form Building Patterns

Hero Hook Form supports multiple patterns. Choose the one that fits your style:

đź’ˇ Tip

Best for: Most use cases. Simple, explicit, and easy to read.

import { FormFieldHelpers } from "@rachelallyson/hero-hook-form"; const fields = [ FormFieldHelpers.input("firstName", "First Name"), FormFieldHelpers.input("lastName", "Last Name"), FormFieldHelpers.input("email", "Email", "email"), FormFieldHelpers.textarea("message", "Message"), FormFieldHelpers.select("country", "Country", [ { label: "Select a country", value: "" }, { label: "United States", value: "us" }, { label: "Canada", value: "ca" }, ]), FormFieldHelpers.checkbox("newsletter", "Subscribe to newsletter"), ];

Method 2: Builder Pattern

đź’ˇ Tip

Best for: Complex forms with many fields. Fluent API with method chaining.

import { createBasicFormBuilder } from "@rachelallyson/hero-hook-form"; const fields = createBasicFormBuilder() .input("firstName", "First Name") .input("lastName", "Last Name") .input("email", "Email", "email") .textarea("message", "Message") .select("country", "Country", [ { label: "Select a country", value: "" }, { label: "United States", value: "us" }, { label: "Canada", value: "ca" }, ]) .checkbox("newsletter", "Subscribe to newsletter") .build();

Method 3: Common Fields

đź’ˇ Tip

Best for: Quick prototyping. Pre-built field collections.

import { CommonFields, FormFieldHelpers } from "@rachelallyson/hero-hook-form"; const fields = [ ...CommonFields.personal(), // firstName, lastName, email FormFieldHelpers.textarea("message", "Message"), ...CommonFields.terms(), // newsletter, terms ];
ℹ️ Info

Not sure which pattern to use? Check out the Form Patterns Comparison guide for a detailed comparison.

Advanced Features

Type-Inferred Forms

import { defineInferredForm, field } from "@rachelallyson/hero-hook-form"; const form = defineInferredForm({ name: field.string("Name").min(2), email: field.email("Email"), age: field.number("Age").min(18), newsletter: field.boolean("Subscribe to newsletter"), }); // Use the form <ZodForm config={form} onSubmit={handleSubmit} />

Dynamic Forms

import { ConditionalField, FieldArrayField } from "@rachelallyson/hero-hook-form"; const fields = [ FormFieldHelpers.input("name", "Name"), FormFieldHelpers.checkbox("hasPhone", "I have a phone number"), ConditionalField({ name: "phone", label: "Phone Number", type: "input", condition: (values) => values.hasPhone, }), FieldArrayField({ name: "addresses", fields: [ FormFieldHelpers.input("street", "Street"), FormFieldHelpers.input("city", "City"), ], addButtonText: "Add Address", }), ];

Custom Validation

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

Form Layouts

Vertical Layout (Default)

<ZodForm config={{ schema, fields }} layout="vertical" spacing="4" />

Grid Layout

<ZodForm config={{ schema, fields }} layout="grid" columns={2} spacing="4" />

Horizontal Layout

<ZodForm config={{ schema, fields }} layout="horizontal" spacing="4" />

Error Handling

Client-Side Validation

const schema = z.object({ email: z.string().email("Please enter a valid email"), name: z.string().min(2, "Name must be at least 2 characters"), });

Server-Side Errors

import { applyServerErrors } from "@rachelallyson/hero-hook-form"; const handleSubmit = async (data) => { try { await submitToServer(data); } catch (error) { // Apply server errors to form applyServerErrors(form, error.fieldErrors); } };

Custom Error Display

<ZodForm config={{ schema, fields }} errorDisplay="toast" // or "modal", "inline", "none" onError={(errors) => console.log("Validation errors:", errors)} />

Performance Optimization

Debounced Validation

import { useDebouncedValidation } from "@rachelallyson/hero-hook-form"; function MyComponent() { const { debouncedValue, isDebouncing } = useDebouncedValidation( value, { delay: 300 } ); // Use debouncedValue for expensive operations }

Memoized Components

import { memo } from "react"; const MyField = memo(({ name, label }) => { return <InputField name={name} label={label} />; });

Testing

Form Test Utilities

import { createFormTestUtils } from "@rachelallyson/hero-hook-form"; const testUtils = createFormTestUtils(form); // Test form submission await testUtils.submitForm(); // Get field value const fieldValue = testUtils.getField("fieldName"); // Set field value testUtils.setFieldValue("fieldName", "new value");

Cypress Integration

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

Next Steps

Now that you’ve created your first form, explore more features:

Last updated on