Roboto Studio
The Sanity & Next.js experts
On the fly form generation with Sanity & Formspark
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,
}
},
},
}
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(),
},
],
};
'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:
textareas
, text inputs
, email inputs
, etcIt'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?
The Sanity & Next.js experts
Founder @ Roboto Studio - The Sanity & Next.js experts
Sr. Full Stack Developer at Roboto Studio
Thinking about getting started with AI? Well we're just going to share our latest and greatest prompt so you don't have to do the hard work
Go to Cursor PromptIf 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 ContentLess is more - We're breaking down some of the core helpers we use when building our websites
Go to GROQ Readability Helper 🤓Okay, well it might be at least in the top 3. Using getDimensions and optimising the hell out of your images, check out this snippet
Go to The best Next.js & Sanity <Image/> Component