Form Builder with React, React-hook-form, and Contentful Headless CMS
Title: Build a Form Builder with React, React-hook-form, and Contentful Headless CMS
Introduction
In this guide, we'll be integrating React-hook-form with Contentful Headless CMS to create a powerful form builder that can store and manage form schema, submissions, and validations.
Here's a step-by-step guide to setting up a form builder with React, React-hook-form, and Contentful.
Prerequisites
1. A Contentful account and a content model for form schema.
2. React components implemented as needed.
Form Schema
This is the recommended high-level schema to implement in Contentful collections
interface FormConfig {
formId: string;
fields: FieldConfig[];
layout?: FormLayout;
logic?: FormLogic;
}
interface FieldConfig {
key: string;
type: InputType;
label?: string;
isDisabled?: boolean;
isRequired?: boolean;
options?: Option[];
defaultValue?: any;
children?: { fields: FieldConfig[] };
Field?: Field;
}
## Step 1: Install dependencies
First, let's install the necessary dependencies for our project:
npm install react-hook-form contentful
## Step 2: Set up Contentful client
Now, let's set up the Contentful client to fetch form schema data:
// contentfulClient.js
import { createClient } from 'contentful';
const client = createClient({
space: process.env.CONTENTFUL_SPACE_ID,
accessToken: process.env.CONTENTFUL_ACCESS_TOKEN,
});
export default client;
Don't forget to store your Contentful Space ID and Access Token in your project's environment variables.
## Step 3: Fetch form schema from Contentful
Next, we'll fetch the form schema from Contentful and pass it as a prop to our form component:
// FormContainer.js
import React, { useState, useEffect } from 'react';
import contentfulClient from './contentfulClient';
import FormBuilder from './FormBuilder';
const FormContainer = () => {
const [formSchema, setFormSchema] = useState(null);
useEffect(() => {
contentfulClient.getEntries({ content_type: 'formSchema' })
.then(response => {
if (response.items.length > 0) {
setFormSchema(response.items[0].fields);
}
})
.catch(error => console.error(error));
}, []);
return (
<div>
{formSchema ? <FormBuilder schema={formSchema} /> : <p>Loading...</p>}
</div>
);
};
export default FormContainer;
## Step 4: Create FormBuilder component
Now let's create the `FormBuilder` component that renders the form fields based on the fetched schema:
// FormBuilder.js
import React from 'react';
import { useForm } from 'react-hook-form';
const FormBuilder = ({ schema }) => {
const { register, handleSubmit, formState: { errors } } = useForm();
const onSubmit = (data) => {
// Process form data here
};
return (
<form onSubmit={handleSubmit(onSubmit)}>
{schema.fields.map((field, index) => (
<div key={index}>
<label htmlFor={field.name}>{field.label}</label>
<input
id={field.name}
{...register(field.name, {
required: field.required,
pattern: field.validationPattern,
})}
/>
{errors[field.name] && <p>{field.errorMessage}</p>}
</div>
))}
<button type="submit">Submit</button>
</form>
);
};
export default FormBuilder;
## Step 5: Save form submissions to Contentful
Finally, let's save the form submissions back to Contentful:
// FormBuilder.js
import React from 'react';
import { useForm } from 'react-hook-form';
import contentfulClient from './contentfulClient';
const FormBuilder = ({ schema }) => {
const { register, handleSubmit, formState: { errors } } } = useForm();
const onSubmit = (data) => {
// Create a new form submission entry in Contentful
contentfulClient.getSpace(process.env.CONTENTFUL_SPACE_ID)
.then(space => space.createEntry('formSubmission', {
fields: {
formData: {
'en-US': JSON.stringify(data)
}
}
}))
.then(entry => {
console.log('Form submission saved:', entry.sys.id);
// Perform any other actions you want after form submission (e.g., show a success message)
})
.catch(error => console.error('Error saving form submission:', error));
};
return (
<form onSubmit={handleSubmit(onSubmit)}>
{schema.fields.map((field, index) => (
<div key={index}>
<label htmlFor={field.name}>{field.label}</label>
<input
id={field.name}
{...register(field.name, {
required: field.required,
pattern: field.validationPattern,
})}
/>
{errors[field.name] && <p>{field.errorMessage}</p>}
</div>
))}
<button type="submit">Submit</button>
</form>
);
};
export default FormBuilder;
With these steps, you have successfully set up a form builder using React, React-hook-form, and Contentful Headless CMS. This form builder will render form fields based on the fetched schema from Contentful and save form submissions back to Contentful as well.
Tutim - The open-source headless wizard form infrastructure
You can also use Tutim as your fully-featured form builder with Contentful.
An open-source, headless, API-first platform that empowers developers and product teams to create and optimize in-app user flows, such as new user onboarding wizards.
Tutim supports multi-step forms, conditional branching, custom validation, localization, and more – all through a JSON schema.