Frequently Asked Questions
Common questions and answers about El Form.
General Questions
What is El Form?
El Form is a React form library that combines the power of Zod schema validation with automatic form generation and flexible form controls. It provides both AutoForm for rapid development and useForm for complete control.
How is El Form different from other form libraries?
El Form focuses on:
- Type Safety First: Built around Zod schemas for runtime and compile-time validation
- Auto-Generation: Create complete forms from schemas with zero boilerplate
- Developer Experience: Excellent TypeScript inference and intuitive APIs
- Performance: Optimized rendering with minimal re-renders
- Flexibility: Easy to customize without fighting the library
Is El Form production-ready?
Yes! El Form is designed for production use with comprehensive testing, TypeScript support, and performance optimizations.
Installation & Setup
What are the peer dependencies?
El Form requires:
react>= 16.8.0zod>= 3.0.0
npm install el-form zod
Can I use El Form with TypeScript?
Absolutely! El Form is built with TypeScript and provides excellent type inference. Your form data is automatically typed based on your Zod schema.
Does El Form work with Next.js?
Yes, El Form works perfectly with Next.js, including SSR and SSG. No special configuration needed.
AutoForm Questions
How do I customize field rendering?
Use the fieldConfig prop to customize individual fields:
<AutoForm
schema={schema}
fieldConfig={{
email: {
label: "Email Address",
placeholder: "you@example.com",
fieldType: "email",
className: "custom-field-class",
},
}}
onSubmit={handleSubmit}
/>
Can I override the submit button?
Yes, use the submitButton prop:
<AutoForm
schema={schema}
submitButton={{
text: "Create Account",
className: "bg-blue-600 text-white px-6 py-2 rounded",
}}
onSubmit={handleSubmit}
/>
How do I handle complex field types?
El Form automatically infers field types from your schema:
const schema = z.object({
text: z.string(), // text input
email: z.string().email(), // email input
number: z.number(), // number input
date: z.date(), // date input
boolean: z.boolean(), // checkbox
enum: z.enum(["a", "b", "c"]), // select dropdown
});
You can override the inferred type:
fieldConfig={{
text: { fieldType: 'textarea' }, // Override to textarea
enum: { fieldType: 'radio' }, // Override to radio buttons
}}
Can I add custom validation?
Yes, use Zod's powerful validation methods:
const schema = z
.object({
password: z
.string()
.min(8, "Must be at least 8 characters")
.regex(
/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)/,
"Must contain uppercase, lowercase, and number"
),
confirmPassword: z.string(),
})
.refine((data) => data.password === data.confirmPassword, {
message: "Passwords don't match",
path: ["confirmPassword"],
});
useForm Questions
When should I use useForm instead of AutoForm?
Use useForm when you need:
- Complete control over form rendering
- Custom form layouts
- Integration with existing components
- Complex conditional logic
- Custom error handling
How do I handle form state?
The useForm hook provides comprehensive form state:
const {
register,
handleSubmit,
watch,
formState: { errors, isDirty, isValid, isSubmitting },
} = useForm({ schema });
// Watch specific fields
const email = watch("email");
// Check if form is dirty
if (isDirty) {
// Form has been modified
}
Can I set default values?
Yes, provide default values in the useForm options:
const { register } = useForm({
schema,
defaultValues: {
name: "John Doe",
email: "john@example.com",
},
});
How do I reset the form?
Use the reset function:
const { reset } = useForm({ schema });
// Reset to default values
reset();
// Reset with new values
reset({ name: "New Name" });
Validation Questions
How do I handle async validation?
For async validation, handle it in your submit function:
const onSubmit = async (data) => {
try {
// Custom async validation
const isEmailTaken = await checkEmailExists(data.email);
if (isEmailTaken) {
setError("email", {
type: "manual",
message: "Email already exists",
});
return;
}
// Submit form
await submitForm(data);
} catch (error) {
// Handle submission errors
}
};
Can I validate on field change?
Yes, configure the validation mode:
const { register } = useForm({
schema,
mode: "onChange", // 'onSubmit' | 'onBlur' | 'onChange' | 'onTouched'
});
How do I show custom error messages?
Define custom messages in your Zod schema:
const schema = z.object({
name: z.string().min(1, "Please enter your name"),
age: z.number().min(18, "You must be at least 18 years old"),
});
Styling Questions
How do I style forms?
El Form is styling-agnostic. You can use:
- CSS Classes: Pass
classNameprops - CSS-in-JS: Any CSS-in-JS solution
- Tailwind CSS: Perfect integration
- Styled Components: Works seamlessly
<AutoForm
schema={schema}
className="max-w-md mx-auto"
fieldConfig={{
name: {
className: "mb-4",
inputClassName: "w-full p-2 border rounded",
labelClassName: "block font-medium mb-1",
},
}}
/>
Can I use custom components?
Yes, with useForm you have complete control:
function CustomForm() {
const { register, handleSubmit } = useForm({ schema });
return (
<form onSubmit={handleSubmit(onSubmit)}>
<MyCustomInput {...register("name")} />
<MyCustomSelect {...register("category")} />
<MyCustomButton type="submit">Submit</MyCustomButton>
</form>
);
}
Performance Questions
How does El Form optimize performance?
El Form uses several optimization techniques:
- Minimal re-renders: Only re-renders affected components
- Efficient validation: Validates only changed fields
- Smart dependencies: Uses React's dependency arrays effectively
- Memoization: Memoizes expensive operations
Should I worry about bundle size?
El Form is designed to be lightweight:
- Core library is small
- Tree-shakeable
- No heavy dependencies
- Zod is the only peer dependency
How do large forms perform?
El Form handles large forms efficiently:
- Use
React.memofor complex field components - Consider field-level validation modes
- Implement virtualization for very large lists
Migration Questions
Can I migrate from React Hook Form?
Yes! The APIs are similar. Main differences:
- El Form uses Zod schemas instead of resolver
registerreturns the same props- Form state structure is nearly identical
How do I migrate from Formik?
Migration is straightforward:
- Replace Yup schemas with Zod
- Use
useForminstead ofuseFormik - Similar validation and submission patterns
Developer Experience
Why is canSubmit a boolean instead of a function?
El Form provides canSubmit as a computed boolean property for better developer experience:
const { canSubmit } = useForm({ schema });
// Good - Direct boolean usage
<button disabled={!canSubmit}>Submit</button>;
// No need to call a function every render
// <button disabled={!canSubmit()}>Submit</button>
This approach:
- Reduces function calls in your JSX
- Makes the API more intuitive
- Follows React patterns for computed state
How does automatic type coercion work?
El Form automatically handles type conversion for number inputs:
const schema = z.object({
age: z.number(), // No need for z.coerce.number()
});
// Empty input → undefined (validation can catch required fields)
// "25" → 25 (automatic conversion to number)
// "abc" → "abc" (invalid, let Zod validation handle it)
Benefits:
- No need to manually use
z.coerce.number() - Empty inputs don't become
0unexpectedly - Cleaner schema definitions
- Better user experience with number fields
Why don't I need z.coerce for numbers?
El Form handles number input coercion automatically:
// You write:
const schema = z.object({
price: z.number().min(0),
});
// El Form automatically converts valid number strings to numbers
// Invalid inputs are left as strings for Zod to validate
This eliminates the need for manual coercion in most cases while maintaining type safety.
Troubleshooting
Form validation isn't working
- Check your Zod schema is correct
- Ensure you're using the latest version
- Verify field names match schema keys
- Check for TypeScript errors
TypeScript errors with form data
- Ensure Zod schema is properly typed
- Use
z.infer<typeof schema>for type inference - Check for optional vs required fields
- Verify enum values match exactly
Performance issues
- Use
React.memofor expensive components - Consider validation mode (
onChangevsonSubmit) - Implement field-level optimization
- Check for unnecessary re-renders with React DevTools
Still need help?
- Check our GitHub Issues
- Join our Discord community (Coming Soon)
- Read the examples for common patterns