@siphesihle_thomo/form-generator
v1.0.0
Published
A schema driven form generator for React
Maintainers
Readme
@form-generator/core
A schema-driven form generator for React applications that combines the power of Zod for validation, React Hook Form for form state management, and customizable field renderers.
Features
- 🎯 Schema-driven: Define your form structure using Zod schemas
- 🔧 Type-safe: Full TypeScript support with automatic type inference
- 🎨 Customizable: Extensible field renderers for any UI component
- ⚡ Performance: Built on React Hook Form for optimal performance
- 🎨 Styling: Built-in Tailwind CSS classes with custom styling support
- 🔌 Flexible: Support for custom field types and renderers
Installation
npm install @form-generator/core
# or
yarn add @form-generator/core
# or
pnpm add @form-generator/corePeer Dependencies
This package requires the following peer dependencies:
npm install react react-dom zod react-hook-form @hookform/resolversQuick Start
import React from 'react';
import { z } from 'zod';
import { FormGenerator } from '@form-generator/core';
// Define your form schema
const userSchema = z.object({
name: z.string().min(2, 'Name must be at least 2 characters'),
email: z.string().email('Invalid email address'),
password: z.string().min(8, 'Password must be at least 8 characters'),
});
// Define your field configurations
const fieldConfigs = [
{
name: 'name',
label: 'Full Name',
type: 'text',
placeholder: 'Enter your full name',
required: true,
},
{
name: 'email',
label: 'Email Address',
type: 'email',
placeholder: 'Enter your email',
required: true,
},
{
name: 'password',
label: 'Password',
type: 'password',
placeholder: 'Enter your password',
required: true,
},
];
function App() {
const handleSubmit = (data: z.infer<typeof userSchema>) => {
console.log('Form data:', data);
// Handle form submission
};
return (
<div className="max-w-md mx-auto mt-8 p-6">
<h1 className="text-2xl font-bold mb-6">User Registration</h1>
<FormGenerator
schema={userSchema}
fieldConfigs={fieldConfigs}
onSubmit={handleSubmit}
submitText="Create Account"
/>
</div>
);
}
export default App;API Reference
FormGenerator
The main component that renders the form based on your schema and field configurations.
Props
| Prop | Type | Required | Description |
|------|------|----------|-------------|
| schema | z.ZodType<any, any> | ✅ | Zod schema for form validation |
| fieldConfigs | FieldProps[] | ✅ | Array of field configurations |
| onSubmit | (data: any) => void | ✅ | Callback function called on form submission |
| className | string | ❌ | CSS classes for the form container |
| submitText | string | ❌ | Text for the submit button (default: "Submit") |
| submitVariant | "default" \| "destructive" \| "outline" | ❌ | Button styling variant |
| submitClassName | string | ❌ | Custom CSS classes for submit button |
| customRenderers | Partial<Record<FieldType, FieldRenderer>> | ❌ | Custom field renderers |
FieldProps
Configuration object for individual form fields.
interface FieldProps {
name: string; // Field name (must match schema)
label?: string; // Field label
type?: FieldType; // Field type
placeholder?: string; // Input placeholder
options?: Option[]; // Options for select/radio fields
required?: boolean; // Whether field is required
disabled?: boolean; // Whether field is disabled
styles?: { // Custom CSS classes
container?: string;
label?: string;
input?: string;
error?: string;
};
render?: FieldRenderer; // Custom renderer function
}Field Types
Currently supported field types:
text- Text inputemail- Email inputpassword- Password inputnumber- Number inputcheckbox- Checkbox inputradio- Radio button groupselect- Select dropdowntextarea- Textarea
useForm Hook
A custom hook that provides form methods with Zod validation.
import { useForm } from '@form-generator/core';
const formMethods = useForm(schema);Advanced Usage
Custom Field Renderers
You can create custom renderers for specific field types:
import React from 'react';
import { FormGenerator, FieldProps } from '@form-generator/core';
const customRenderers = {
textarea: ({ name, label, placeholder, required }: FieldProps) => (
<div className="mb-4">
{label && (
<label htmlFor={name} className="block mb-1 font-medium text-sm text-gray-700">
{label}
</label>
)}
<textarea
id={name}
name={name}
placeholder={placeholder}
required={required}
className="w-full border rounded px-3 py-2 focus:outline-none focus:ring focus:ring-black min-h-[100px]"
/>
</div>
),
select: ({ name, label, options, required }: FieldProps) => (
<div className="mb-4">
{label && (
<label htmlFor={name} className="block mb-1 font-medium text-sm text-gray-700">
{label}
</label>
)}
<select
id={name}
name={name}
required={required}
className="w-full border rounded px-3 py-2 focus:outline-none focus:ring focus:ring-black"
>
<option value="">Select an option</option>
{options?.map((option) => (
<option key={option.value} value={option.value}>
{option.label}
</option>
))}
</select>
</div>
),
};
function App() {
return (
<FormGenerator
schema={schema}
fieldConfigs={fieldConfigs}
onSubmit={handleSubmit}
customRenderers={customRenderers}
/>
);
}Custom Styling
You can customize the styling of individual fields:
const fieldConfigs = [
{
name: 'email',
label: 'Email',
type: 'email',
styles: {
container: 'mb-6',
label: 'block mb-2 text-sm font-semibold text-gray-800',
input: 'w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent',
error: 'mt-1 text-sm text-red-600',
},
},
];Complex Forms
For complex forms with nested objects or arrays:
const complexSchema = z.object({
personalInfo: z.object({
firstName: z.string().min(2),
lastName: z.string().min(2),
email: z.string().email(),
}),
preferences: z.object({
newsletter: z.boolean(),
notifications: z.boolean(),
}),
});
const complexFieldConfigs = [
{
name: 'personalInfo.firstName',
label: 'First Name',
type: 'text',
},
{
name: 'personalInfo.lastName',
label: 'Last Name',
type: 'text',
},
{
name: 'personalInfo.email',
label: 'Email',
type: 'email',
},
{
name: 'preferences.newsletter',
label: 'Subscribe to newsletter',
type: 'checkbox',
},
{
name: 'preferences.notifications',
label: 'Enable notifications',
type: 'checkbox',
},
];Form Validation
The form automatically validates based on your Zod schema:
const validationSchema = z.object({
username: z.string()
.min(3, 'Username must be at least 3 characters')
.max(20, 'Username must be less than 20 characters')
.regex(/^[a-zA-Z0-9_]+$/, 'Username can only contain letters, numbers, and underscores'),
email: z.string()
.email('Please enter a valid email address'),
password: z.string()
.min(8, 'Password must be at least 8 characters')
.regex(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)/, 'Password must contain at least one uppercase letter, one lowercase letter, and one number'),
confirmPassword: z.string(),
}).refine((data) => data.password === data.confirmPassword, {
message: "Passwords don't match",
path: ["confirmPassword"],
});Examples
Login Form
const loginSchema = z.object({
email: z.string().email('Invalid email address'),
password: z.string().min(1, 'Password is required'),
});
const loginFields = [
{
name: 'email',
label: 'Email',
type: 'email',
placeholder: 'Enter your email',
},
{
name: 'password',
label: 'Password',
type: 'password',
placeholder: 'Enter your password',
},
];
<FormGenerator
schema={loginSchema}
fieldConfigs={loginFields}
onSubmit={handleLogin}
submitText="Sign In"
submitVariant="default"
/>Registration Form with Custom Styling
const registrationFields = [
{
name: 'firstName',
label: 'First Name',
type: 'text',
required: true,
styles: {
container: 'mb-4',
label: 'block text-sm font-medium text-gray-700 mb-1',
input: 'w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500',
},
},
{
name: 'lastName',
label: 'Last Name',
type: 'text',
required: true,
},
{
name: 'email',
label: 'Email Address',
type: 'email',
required: true,
},
{
name: 'role',
label: 'Role',
type: 'select',
options: [
{ value: 'user', label: 'User' },
{ value: 'admin', label: 'Administrator' },
{ value: 'moderator', label: 'Moderator' },
],
},
];
<FormGenerator
schema={registrationSchema}
fieldConfigs={registrationFields}
onSubmit={handleRegistration}
submitText="Create Account"
submitVariant="default"
className="max-w-lg mx-auto p-6 bg-white rounded-lg shadow-md"
/>Contributing
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
License
This project is licensed under the MIT License - see the LICENSE file for details.
Support
If you have any questions or need help, please open an issue on GitHub or contact the maintainers.
