@metadiv-studio/metaform
A powerful, flexible React form component built with React Hook Form, Zod validation, and TypeScript. MetaForm provides a declarative way to create complex forms with automatic validation, responsive layouts, and customizable rendering.
🚀 Installation
npm install @metadiv-studio/metaform
📦 Package Description
MetaForm is a comprehensive form solution that combines the power of:
- React Hook Form for efficient form state management
- Zod for runtime validation and type safety
- MetaGrid for responsive form layouts
- TypeScript for full type safety and IntelliSense
Key features:
- ✨ Declarative form definition - Define forms using simple configuration objects
- 🔒 Automatic validation - Built-in Zod schema validation
- 📱 Responsive layouts - Automatic responsive grid system
- 🎨 Customizable rendering - Render any React component as form fields
- 🔄 Form groups - Organize fields into logical sections
- 💡 Tooltips and help text - Built-in support for field descriptions
- 👁️ Conditional visibility - Show/hide fields based on form state
- 🎯 Type safety - Full TypeScript support with inferred types
🛠️ Usage
Basic Example
import MetaForm from '@metadiv-studio/metaform';
import { z } from 'zod';
import { Input } from '@metadiv-studio/input';
const userSchema = z.object({
firstName: z.string().min(2, 'First name must be at least 2 characters'),
lastName: z.string().min(2, 'Last name must be at least 2 characters'),
email: z.string().email('Invalid email address'),
});
const formItems = [
{
name: 'firstName',
label: 'First Name',
required: true,
render: (field) => (
<Input
{...field}
placeholder="Enter first name"
/>
),
},
{
name: 'lastName',
label: 'Last Name',
required: true,
render: (field) => (
<Input
{...field}
placeholder="Enter last name"
/>
),
},
{
name: 'email',
label: 'Email',
required: true,
tooltip: 'We will use this for account notifications',
render: (field) => (
<Input
{...field}
type="email"
placeholder="Enter email address"
/>
),
},
];
function UserForm() {
const handleSubmit = async (values: z.infer<typeof userSchema>) => {
console.log('Form values:', values);
};
return (
<MetaForm
schema={userSchema}
items={formItems}
onSubmit={handleSubmit}
saveButton={true}
saveButtonText="Create User"
/>
);
}
Advanced Example with Form Groups
import MetaForm from '@metadiv-studio/metaform';
import { z } from 'zod';
import { Input } from '@metadiv-studio/input';
import { Select } from '@metadiv-studio/select';
const profileSchema = z.object({
personalInfo: z.object({
firstName: z.string().min(2),
lastName: z.string().min(2),
dateOfBirth: z.string(),
}),
contactInfo: z.object({
email: z.string().email(),
phone: z.string().optional(),
address: z.string(),
}),
preferences: z.object({
newsletter: z.boolean(),
notifications: z.boolean(),
theme: z.enum(['light', 'dark', 'auto']),
}),
});
const formItems = [
{
label: 'Personal Information',
items: [
{
name: 'personalInfo.firstName',
label: 'First Name',
required: true,
render: (field) => <Input {...field} placeholder="First name" />,
},
{
name: 'personalInfo.lastName',
label: 'Last Name',
required: true,
render: (field) => <Input {...field} placeholder="Last name" />,
},
{
name: 'personalInfo.dateOfBirth',
label: 'Date of Birth',
render: (field) => <Input {...field} type="date" />,
},
],
},
{
label: 'Contact Information',
items: [
{
name: 'contactInfo.email',
label: 'Email',
required: true,
tooltip: 'Primary contact email',
render: (field) => <Input {...field} type="email" placeholder="Email" />,
},
{
name: 'contactInfo.phone',
label: 'Phone',
render: (field) => <Input {...field} placeholder="Phone number" />,
},
{
name: 'contactInfo.address',
label: 'Address',
render: (field) => <Input {...field} placeholder="Full address" />,
},
],
},
{
label: 'Preferences',
items: [
{
name: 'preferences.newsletter',
label: 'Newsletter Subscription',
render: (field) => (
<input
type="checkbox"
checked={field.value}
onChange={(e) => field.onChange(e.target.checked)}
/>
),
},
{
name: 'preferences.theme',
label: 'Theme',
render: (field) => (
<Select
value={field.value}
onValueChange={field.onChange}
options={[
{ value: 'light', label: 'Light' },
{ value: 'dark', label: 'Dark' },
{ value: 'auto', label: 'Auto' },
]}
/>
),
},
],
},
];
function ProfileForm() {
const handleSubmit = async (values: z.infer<typeof profileSchema>) => {
console.log('Profile updated:', values);
};
return (
<MetaForm
schema={profileSchema}
items={formItems}
onSubmit={handleSubmit}
saveButton={true}
saveButtonText="Update Profile"
/>
);
}
Example with Data Fetching
import MetaForm from '@metadiv-studio/metaform';
import { z } from 'zod';
import { useEffect } from 'react';
const productSchema = z.object({
name: z.string().min(1, 'Product name is required'),
price: z.number().min(0, 'Price must be positive'),
description: z.string().optional(),
});
function ProductEditForm({ productId }: { productId: string }) {
const fetchProduct = async (id: string) => {
const response = await fetch(`/api/products/${id}`);
const product = await response.json();
form.reset(product);
};
const handleSubmit = async (values: z.infer<typeof productSchema>) => {
await fetch(`/api/products/${productId}`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(values),
});
};
return (
<MetaForm
schema={productSchema}
items={[
{
name: 'name',
label: 'Product Name',
required: true,
render: (field) => <Input {...field} placeholder="Product name" />,
},
{
name: 'price',
label: 'Price',
required: true,
render: (field) => (
<Input
{...field}
type="number"
step="0.01"
placeholder="0.00"
/>
),
},
{
name: 'description',
label: 'Description',
render: (field) => (
<textarea
{...field}
placeholder="Product description"
rows={4}
/>
),
},
]}
fetchId={productId}
fetch={fetchProduct}
onSubmit={handleSubmit}
saveButton={true}
saveButtonText="Update Product"
/>
);
}
🔧 API Reference
MetaForm Props
schema | z.ZodType | Zod schema for form validation |
items | FormItem[] | Array of form field definitions |
defaultValues | Partial<T> | Initial form values |
loading | boolean | Show loading state for all fields |
saveButton | boolean | Show save button |
saveButtonText | string | Custom save button text |
cancelButtonText | string | Custom cancel button text |
onSubmit | (values: T) => Promise<void> | Form submission handler |
onCancel | () => void | Cancel button handler |
onValuesChange | (values: T) => void | Form values change handler |
fetch | (id?: any, form?: UseFormReturn) => Promise<void> | Data fetching function |
fetchId | any | ID for data fetching |
fetchError | (error: any) => void | Error handling for fetch operations |
form | UseFormReturn | External form instance |
FormItem Interface
interface FormItem<T> {
name?: Path<T>;
label?: React.ReactNode;
required?: boolean;
tooltip?: string;
className?: string;
visible?: (form: UseFormReturn) => boolean;
render?: (field: ControllerRenderProps, form: UseFormReturn) => React.ReactNode;
items?: FormItem<T>[];
}
🎨 Styling
MetaForm uses Tailwind CSS for styling. To use the default styles, ensure Tailwind CSS is included in your project and add the following to your tailwind.config.js:
module.exports = {
content: [
"./node_modules/@metadiv-studio/**/*.{js,ts,jsx,tsx}",
],
}
📚 Dependencies
This package has the following peer dependencies:
And requires these packages to be installed in your project:
@hookform/resolvers
zod
react-hook-form
🤝 Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
📄 License
This project is licensed under the UNLICENSED license.