The Form Builder for Developers

The Form Builder for Developers

Coding forms can take hours. It takes minutes with Fetch Forms.

Table of Contents

  1. The form building gap
  2. Fetch Forms intro
  3. The form building process
  4. Code examples

The problem with current developer form tools

There are lots of form builders and form tools available today. Whether you need to share a simple form with family members, build a complex registration form, or gather payment information, there is a form builder or tool for you. Or is there...I see a gap.

Form backend services help JAMstack websites collect form submissions without a server and connect data to 3rd party systems. But you still have to hand build the HTML form and its supporting functions like client-side validation. On top of that, if you want to use the form submissions locally in your code, as well as use a backend service, you can’t!

Code libraries like Formik and Angular Forms are incredibly helpful for managing form state and validation. You can use your own components and build a high-quality form much quicker than with standard HTML. Unfortunately, you still have to spend time hand-building every single form and its validation rules. You also have to spend time creating a backend to handle form submissions and integrate the data.

Forms are too repetitive and time-consuming for developers to constantly be hand-building them.

Fetch Forms

That’s why I built Fetch Forms. I wanted the benefits of a form backend service and to be able to build the forms in a form builder that would remove the repetitive aspects.

The Fetch form builder’s defaults and templates will help you build and collaborate on forms in record time.

The Fetch API will help you integrate high-quality forms with client-side validation into your application in a matter of minutes.

Updates are just as easy. Complete your changes and publish them with a single click. All applications using the updated Fetch form will begin to pull the new form.

Get started with Fetch Forms

Get the speed of a form builder with the control of code. Here’s how:

1. Build

Use the Fetch form builder to create and build your form. It’s packed with templates and defaults to make building forms painless.

  • Select validation rules and input masking
  • Choose whether to save submissions to Fetch Forms
  • Use form and field templates to build forms in record time Fetch form builder

2. Deploy

Deploy your form using any of our NPM modules, the embed script, or by simply using the native fetch API. The possibilities are endless!

  • Install and use the Javascript or React library
  • Use the embed script to drop a form into any web-based tool
  • Extend your own component library A fetch form in code

3. Submissions

You don’t have to send submissions to Fetch Forms — all data submitted is available to your local code no matter what.

If you configured the form to save submissions to the Fetch Forms library, they will be validated on the server and sent through spam filtering. Submissions will then activate any connections you have set up.


How about we look at some code?

Using Fetch Forms can be as simple or as complex as you need. The first two examples are using a styled component provided by Fetch Forms. You can also implement a Fetch form with your own component library - see example 3.

You watch me talk through building and deploying a form in the walkthrough here.

Simple Javascript & HTML example

See more at www.fetchforms.io/docs/fetch-forms-javascript

<!DOCTYPE html>
<html>
  <main style="max-width: 600px; margin: auto">
    <h1>Fetch Forms Javascript</h1>
    <hr />
    <h2 id="form_name" style="margin-bottom: 25px"></h2>
    <div id="fetch_form"></div>
    <pre id="result"></pre>
  </main>
  <script>
    import { renderForm } from "@fetchforms/core";

    // Called when data is submitted
    const onComplete = (data) => {
      document.getElementById("result").innerHTML = JSON.stringify(data, null, 2);
    };

    // Called when the Fetch form is loaded from the API
    const onLoad = (data) => {
      // Set the form name on the HTML 
      document.getElementById("form_name").innerHTML = data.name;
    };

    // Pass in the form slug, element Id to attach the form to, and optional utility functions
    renderForm(
      "__form_slug__",
      "fetch_form",
      onComplete,
      onLoad
    );

  </script>
</html>

Simple React example

See more at www.fetchforms.io/docs/fetch-forms-react

import React, { useState } from "react";
import { FetchForm } from "@fetchforms/react";

const ManagedForm = () => {
  const [formSubmission, setFormSubmission] = useState(null);
  const [formName, setFormName] = useState("");
  const onSubmit = async (values) => {
    /* To show an error on the form, uncomment the line below */
    // return 'There was an error submitting the form.';
    setFormSubmission(values);
  };

  const onLoad = async (values) => {
    setFormName(values.name);
  };

  return (
    <div className="">
      <div className="text-3xl mb-2">Component Form</div>
      <p className="text-gray-600">
        The easiest way to use Fetch Forms. Pass in a form slug and we'll handle
        client-side validation, input formatting, submissions, and styling.
      </p>
      <br />
      <div>
        <h2 className="text-2xl">{formName}</h2>
        <FetchForm slug={__form_slug__} onSubmit={onSubmit} onLoad={onLoad} />
        <br />
        {formSubmission && <pre>{JSON.stringify(formSubmission, null, 2)}</pre>}
      </div>
    </div>
  );
};

With custom components example

This example is using Ant Design as the component library.

See a full working example at www.fetchforms.io/docs/fetch-forms-react

import React, { useState } from "react";
import "antd/dist/antd.css";
import { useFetchForms } from "@fetchforms/react";
import { Form, Input, Button, Checkbox, Select, Radio, InputNumber, Alert } from "antd";

const CustomFetchForm = () => {
  const [fetchForm, loading, error, doCloudSubmit] = useFetchForms("__form_slug__");

  // Called when submission passes client-side validation
  const onFinish = async (values) => {
    if (fetchForm.cloudSave) {
      console.log("Saving to the Fetch Form's cloud");
      try {
        const isSaved = await doCloudSubmit(fetchForm.id, values);
        if (!isSaved) {
          throw new Error("There was an error submitting your form.");
        }
      } catch (err) {
        console.error(err);
      }
    }
  };

  const onFinishFailed = (errorInfo) => {
    console.log("Failed:", errorInfo);
  };

  // This takes the validation rules from the Fetch form and formats them for 
  // the Ant Design form component.
  const createValidationRules = (fieldType, validations) => {
    const rules = validations.map((validation) => {
      if (validation.rule === "required") {
        return { required: true, message: validation.message };
      } else if (validation.rule === "regex") {
        return {
          pattern: new RegExp(validation.limit),
          message: validation.message
        };
      } else {
        return {
          [validation.rule]: validation.limit,
          message: validation.message,
          type: fieldType === "number" ? "number" : "string"
        };
      }
    });
    return rules;
  };

  // Builds out the field based on it's configuration
  const dynamicField = (item) => {
    switch (item.fieldType) {
      case "select":
        const { Option } = Select;
        return (
          <Select key={item.name}>
            <Option value=""></Option>
            {item.options.map((option) => (
              <Option value={option.value} key={option.value}>
                {option.label}
              </Option>
            ))}
          </Select>
        );
      case "checkbox":
        return <Checkbox key={item.name} />;
      case "textarea":
        const { TextArea } = Input;
        return <TextArea key={item.name} />;
      case "number":
        return <InputNumber key={item.name} />;
      case "radio":
        return (
          <Radio.Group>
            {item.options.map((opt) => (
              <Radio value={opt.value} key={opt.value}>
                {opt.label}
              </Radio>
            ))}
          </Radio.Group>
        );
      default:
        return <Input {...item.fieldHtml} key={item.name} />;
    }
  };

  return (
    <div className="">
      {loading ? (
        <div>Loading...</div>
      ) : (
        fetchForm && (
          <Form
            name="HookForm"
            labelCol={{ span: 6 }}
            wrapperCol={{ span: 18 }}
            onFinish={onFinish}
            onFinishFailed={onFinishFailed}
            autoComplete="off"
            noValidate
          >
            {fetchForm.formItems.map((item, i) => (
              <Form.Item
                key={i}
                label={item.label}
                name={item.name}
                valuePropName={
                  item.fieldType === "checkbox" ? "checked" : "value"
                }
                rules={createValidationRules(item.fieldType, item.validation)}
                validateTrigger="onBlur"
              >
                {dynamicField(item)}
              </Form.Item>
            ))}
            <Form.Item
              wrapperCol={{
                span: 8,
                offset: 6
              }}
            >
              <Button type="primary" htmlType="submit">
                {fetchForm.submitText}
              </Button>
            </Form.Item>
          </Form>
        )
      )}
    </div>
  );
};


Fetch Forms is a headless form builder that exists to help developers build and manage forms easily so they can focus on more important things. It’s perfect for headless websites, JAMstack websites, and web apps.