Go Behind the Experience to see how Tecovas brings the West to life with Sanity 🤠 July 18th

Sanity & Formspark Form Generator

By Roboto Studio & Jono Alford

On the fly form generation with Sanity & Formspark

Form Field Builder

import {FaAlignLeft} from 'react-icons/fa'

export default {
  name: 'formBuilder',
  title: 'Form Builder',
  icon: FaAlignLeft,
  type: 'object',
  fields: [
    {
      name: 'formFields',
      title: 'Form Fields',
      type: 'array',
      of: [{type: 'formFields'}],
    },
  ],
  preview: {
    prepare() {
      return {
        title: `Custom form setup`,
        subtitle: `Form Builder`,
        media: FaAlignLeft,
      }
    },
  },
}

Form Fields

export default {
  name: 'formFields',
  title: 'Form Fields',
  type: 'object',
  fields: [
    {
      name: 'required',
      title: 'Required',
      type: 'boolean',
      initialValue: false,
    },
    {
      name: 'fieldName',
      title: 'Field Name',
      type: 'string',
      validation: Rule => Rule.required(),
    },
    {
      name: 'placeholder',
      title: 'Placeholder',
      type: 'string',
      validation: Rule => Rule.required(),
    },
    {
      name: 'fieldId',
      title: 'Field ID',
      type: 'slug',
      options: {
        source: (doc, options) => options.parent.fieldName,
        maxLength: 200,
      },
      validation: Rule => Rule.required(),
    },
    {
      name: 'inputType',
      title: 'Input Type',
      type: 'string',
      initialValue: 'text',
      options: {
        layout: 'dropdown',
        list: [
          {value: 'text', title: 'Text input'},
          {value: 'email', title: 'Email'},
          {value: 'phone', title: 'Phone number'},
          {value: 'textArea', title: 'Text area'},
          {value: 'file', title: 'File upload'},
        ],
      },
      validation: Rule => Rule.required(),
    },
  ],
};

React Code

'use client';
import { useFormspark } from '@formspark/use-formspark';
import React, { FC, useState } from 'react';
import { useForm } from 'react-hook-form';

const InputField = ({ type, id, fieldName, required, placeholder, register }) => (
  <div>
    <label htmlFor={id}>{fieldName}</label>
    <div>
      <input
        type={type}
        id={id}
        required={!!required}
        placeholder={placeholder}
        aria-describedby={type}
        {...register(id)}
      />
    </div>
  </div>
);

export const FormBuilderBlock = ({ formFields, uid }) => {
  const [submitted, setSubmitted] = useState(false);
  const [submit, submitting] = useFormspark({ formId: 'YOUR_FORMSPARK_ID' });
  const { register, handleSubmit } = useForm();

  const onSubmit = (data) => {
    submit(data);
    setSubmitted(true);
  };

  if (submitted) {
    return (
      <div>
        <h1>Success box</h1>
      </div>
    );
  }

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      {Array.isArray(formFields) &&
        formFields.map((field) => {
          const { inputType, _key, fieldId, placeholder, _type, fieldName, required } = field ?? {};
          const { current } = fieldId ?? {};
          if (!inputType || !current) return null;

          if (inputType === 'textArea') {
            return (
              <div key={_key}>
                <label htmlFor={current}>{fieldName}</label>
                <div>
                  <textarea
                    id={current}
                    required={!!required}
                    placeholder={placeholder}
                    aria-describedby="textarea"
                    {...register(current)}
                  />
                </div>
              </div>
            );
          }

          return (
            <InputField
              key={_key}
              type={inputType}
              id={current}
              fieldName={fieldName}
              required={required}
              placeholder={placeholder}
              register={register}
            />
          );
        })}
      <button type="submit" disabled={submitting}>
        Submit
      </button>
    </form>
  );
};

You're coming from WordPress, and you want to get similar functionality to WP Forms but without the monstrous negative performance cost of actually using WordPress?

Boy gee, do we have some schema to help you out! This piece of code helps you to:

  • Generate forms on the fly
  • Add fields to a form
  • Remove fields from a form
  • Create textareas, text inputs, email inputs, etc
  • Generate an email when somebody submits

It's also using React Server Components, so feel free to drop the "use client" if you're using an older version of React or Next.js.

Oh, and if you're wondering why we're using Formspark? It's because it's got probably the best pricing tier for any form-handling system we've seen. Seriously 50,000 submissions for $25. I honestly don't know how they stay afloat as a business.

Want more great tips on how to structure your Sanity schema, Are you looking to build your company website with Sanity? Want to see what you can achieve with our team of experts?

☎️ Get a meeting booked in

Contributors

Other schemas by authors

Portable Text Mock Content

If you're looking to mockup portable text in Storybook without a Sanity backend, this is the schema you're looking for

Go to Portable Text Mock Content

One or the other validation

This validation can be used if you have two fields and you require one or the other to be filled

Roboto Studio
Go to One or the other validation