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

PropTypeDefaultDescription
schemaFormSchemarequiredThe form schema to render
onSubmit(data: Record<string, any>) => void-Callback when form is submitted
initialDataRecord<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