DEV Community

Cover image for This React component turns a headless CMS into a form builder
James Ellis-Jones
James Ellis-Jones

Posted on • Originally published at

This React component turns a headless CMS into a form builder

Many CMSs and SaaS services will let non-technical users build forms to their requirements for data collection. While headless CMSs often power the content of React applications, this form builder functionality is not something really associated with React. This article shows you how you can create a React application with a form whose structure is data driven and can be managed by non-technical users through a CMS interface. To do this, we will use tools which are part of the Restspace project.

The first thing we need is a means to build a form in React whose structure is data driven. We will use Restspace's Schema Form package. This package contains a component which renders a form whose structure and validation is determined by a JSON Schema. It's highly capable and can render a wide range of components including custom React components, and generate structured forms with lists and subforms, conditional fields etc. and even recursive forms.

Architecture Diagram

Any headless CMS which is capable of storing a JSON Schema object is capable of supplying the form definition schema. We're going to use Restspace, a low code API, service and content platform, to do this. Restspace uses JSON Schema as the structure definition for its data store, and the schema is available via Restspace's API. The application containing the form can therefore read the schema from the API, allowing it to act as a single source of truth. The schema can be edited via a form-based interface in Restspace's admin UI, so non-technical users can do this.

In addition, Restspace allows non-technical users to view and edit submitted form data via a form constructed using components from the Schema Form package in its admin UI. This makes a great setup for management of user-entered data such as an onboarding process.

Now we'll describe the steps involved in building this.

Create the React project

Create a React project using create-react-app in the usual way:

npx create-react-app json-schema-form-demo
or npx create-react-app json-schema-form-demo --template typescript
Enter fullscreen mode Exit fullscreen mode

We're going to use Typescript in this article, it should be easy enough to take out the types to get vanilla JS if that's what you prefer. The next step is to install the Restspace Schema Form package:

npm install @restspace/schema-form
Enter fullscreen mode Exit fullscreen mode

Now create a form with a preset JSON Schema, to see it working without being connected to an API. Replace the contents of App.tsx with the code below:

import React from 'react';
import "@restspace/schema-form/build/index.css";
import "@restspace/schema-form/src/css/default-skin.css";
import { SchemaSubmitForm } from '@restspace/schema-form';

function App() {
  const schema = {
    type: "object",
    properties: {
      "firstName": { type: "string" },
      "lastName": { type: "string" }
  const value = {};

  const onDoSubmit = async (val: object) => {
    alert(JSON.stringify(val, null, 4));
    return true;

  return (
    <div className="App">
      <SchemaSubmitForm {...{ schema, value }}
          makeSubmitLink={(onClick) => (
            <button type="button" className='sf-submit-button'

export default App;
Enter fullscreen mode Exit fullscreen mode

Tip: if you're using VS Code and see a syntax error marked, it's probably because your Typescript versions are out of sync. Click CTRL + SHIFT + P and select 'Typescript: Select Typescript Version'. Choose 'Use Workspace Version' and the problem should go away.

The variable schema is a JSON schema defining the form structure. The onDoSubmit function handles the user's click of the submit button, receiving the current form value as an object with properties for the field values. The makeSubmitLink prop is set to a function that when given a handler for a click of the button, returns a React element to be used to render the submit button. SchemaSubmitForm is the component which renders the form.

This demonstrates how the form works without it being connected to a source for the schema.

Set up Restspace

Now go to the Restspace home page, click the GET YOUR INSTANCE button a little way down the page, and fill in the short registration form, choosing a unique subdomain for your Restspace account. Within a couple of minutes, you'll receive a confirmation email (remember to check your Junk folder!). Click the 'Activate Account' link to return to the Restspace site, you'll see this page:

Restspace acknowledgement

Click the top link for the Admin interface. Log in with the email and password you gave at registration. You'll see the admin UI. Expand the JSON section on the left and click the folder-shaped '+' button (not the round button).

Create directory

Enter a name for the new directory, we'll choose 'schema-form' and hit return. Then click on the 'schema-form' directory heading which appears and you'll see this appear on the right for entering the schema for the data in this directory:

create schema

You can create the schema by using a form in the tab you can see open on the right. If you click the second tab, it will give you a text editor into which you can enter any JSON schema. The form editor is somewhat limited in the schemas it will let you create. But it will be fine for this demo. Click the '+' button twice to add two fields and fill them out as shown below, then click SUBMIT.

create schema done

You've now created a schema which governs the structure of JSON files to be stored in this directory. You can read this schema from the url /json/schema-form/schema.config.json.

Integrating front-end and back-end

Now we'll go back to the React project and amend it to read the schema:

const restspaceBase = '';

function App() {
  const [schema, setSchema] = useState({} as object);

  useEffect(() => {
    (async () => {
      const resp = await fetch(restspaceBase +
      if (resp.ok) {
        const newSchema = await resp.json();
  }, []);

  const value = {};
Enter fullscreen mode Exit fullscreen mode

We add hooks to the App component to store the schema as state, and to initially run a request to fetch the schema from Restspace. Make sure to change the subdomain of restspaceBase to the subdomain you created. Also you'll need to add useEffect and useState to the import for React.

You can run this and it should show the same form it did before.

Now let's add a bit more code to send the entered data to Restspace. We replace the part which sets the const onDoSubmit:

const onDoSubmit = async (val: object) => {
  const entryTimestamp = new Date().toISOString();
  await fetch(restspaceBase + 'json/schema-form/' + entryTimestamp, {
    method: 'PUT',
    body: JSON.stringify(val),
    headers: {
      "Content-Type": "application/json"
  return true;
Enter fullscreen mode Exit fullscreen mode

This makes a PUT request to the schema-form folder with the entered data using a resource name made from the current time. This means form data will be listed in created time order. For this to work, we also need to loosen permissions in Restspace to allow unauthenticated writing. Go back to the Restspace admin screen and click the grey bar at the top left titled with the subdomain of your Restspace site. You'll see the service list:

Restspace service list

Now click the edit button (pencil) on the top right of the panel for the JSONSERVICE. This opens the service editor panel. In the Write roles field add /schema-form all to enable just the schema-form directory to be writable by all users.

Json service authorization

Now click SUBMIT then click the Commit Changes button on the top right. Click OK to the confirmation and the page will refresh with the new settings. You can now go back to the React application and try entering data into the form and saving it.

Enter data into form

Enter values in the fields and click SUBMIT. Now go back to Restspace. Click the expander beside the schema-form item in the directory tree on the left twice to close and open it, which will refresh the listing of the directory.

Saved data

Now let's change the form from Restspace's admin UI. Click on the schema-form item in the tree navigation on the left. In the fields form, we are going to add the 'title' item shown. Notice in this case, you have a static, limited number of items in the drop down which you supply as a bar-separated list. Click the plus at the bottom of the form, fill in the fields, and use the up-arrow button to move it to the top. Then click SUBMIT to update the schema.

Update schema

Then return to the React project, refresh the page and you'll see the form update.

Updated form

Exploring further

To learn more about how the schema-form components work and how they support JSON Schema see the ReadMe at

You can host the React application you just created using Restspace. Create a static site hosting service by clicking the grey bar at the top left of the admin site, clicking Add Service at the top left of the main pane, then scrolling down the service catalogue that appears to the right, until you find StaticSite. Click the block and you then get a form to fill in the configuration. Below is an example for a creating a React site on the root path:

Static site configuration

Click SUBMIT - the static site will be created at the bottom of the list of services which it will only handle urls which don't match any of the others above it. Then click Commit Changes on the top right to create the static site service. Once this is done, when you click on the name of the static site service ('Site') in the navigator on the left, you'll get a page where you can upload the site.

To do this, build the React site and make a zip including all the top level files and directories in the build or dist directory. Then upload this zip to the static site service and it will be deployed to your Restspace domain. Go to the homepage of your domain and you will now be able to see the form.

Follow me on Twitter if you want to keep up with Restspace and get my React and general CS tips.

Top comments (0)