FormViewer
The FormViewer component renders forms for end users based on a schema created with FormBuilder.
Basic Usage
tsx
import { FormViewer } from '@formmorf/builder';
import '@formmorf/builder/dist/style.css';
function ContactForm({ schema }) {
const handleSubmit = (data) => {
console.log('Form submitted:', data);
// Send to backend
};
return (
<FormViewer
schema={schema}
onSubmit={handleSubmit}
/>
);
}Props
| Prop | Type | Default | Description |
|---|---|---|---|
| schema | FormSchema | required | The form schema to render |
| onSubmit | (data: Record<string, any>) => void | - | Callback when form is submitted |
| initialData | Record<string, any> | {} | Initial form values |
Features
- ✓Automatic Validation: Validates all fields based on schema rules
- ✓Error Display: Shows validation errors inline below fields
- ✓Conditional Fields: Show/hide fields based on other field values
- ✓Material-UI Styling: Beautiful, accessible components out of the box
- ✓Responsive: Works perfectly on mobile, tablet, and desktop
With Initial Data
Pre-fill form fields with existing data (for edit forms):
tsx
function EditContactForm({ contactId }) {
const [schema, setSchema] = useState(null);
const [initialData, setInitialData] = useState({});
useEffect(() => {
// Load schema and contact data
Promise.all([
fetch('/api/form-schema').then(r => r.json()),
fetch(`/api/contacts/${contactId}`).then(r => r.json())
]).then(([formSchema, contact]) => {
setSchema(formSchema);
setInitialData({
fullName: contact.name,
email: contact.email,
phone: contact.phone,
message: contact.notes
});
});
}, [contactId]);
const handleSubmit = (data) => {
fetch(`/api/contacts/${contactId}`, {
method: 'PUT',
body: JSON.stringify(data)
});
};
if (!schema) return <div>Loading...</div>;
return (
<FormViewer
schema={schema}
initialData={initialData}
onSubmit={handleSubmit}
/>
);
}Handling Submission
Complete example with loading states and error handling:
tsx
function ContactForm({ schema }) {
const [isSubmitting, setIsSubmitting] = useState(false);
const [submitError, setSubmitError] = useState(null);
const [submitSuccess, setSubmitSuccess] = useState(false);
const handleSubmit = async (data) => {
setIsSubmitting(true);
setSubmitError(null);
try {
const response = await fetch('/api/contact', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data)
});
if (!response.ok) throw new Error('Submit failed');
setSubmitSuccess(true);
// Reset form or redirect
setTimeout(() => {
window.location.href = '/thank-you';
}, 2000);
} catch (error) {
setSubmitError(error.message);
} finally {
setIsSubmitting(false);
}
};
return (
<div>
{submitSuccess && (
<div className="mb-4 rounded bg-green-100 p-4 text-green-800">
Form submitted successfully!
</div>
)}
{submitError && (
<div className="mb-4 rounded bg-red-100 p-4 text-red-800">
Error: {submitError}
</div>
)}
<FormViewer
schema={schema}
onSubmit={handleSubmit}
/>
{isSubmitting && (
<div className="mt-4 text-center text-muted-foreground">
Submitting...
</div>
)}
</div>
);
}Validation
FormViewer automatically validates fields based on the schema. No additional code needed!
- • Required fields: Checked before submission
- • Email validation: Validates email format
- • Number ranges: Min/max validation for numbers
- • String length: Min/max length for text fields
- • Pattern matching: Regex validation support
- • Custom validators: Add your own validation logic
Explore Field Types
Learn about all 20+ available field types and their properties
Field Types Documentation