Reference

What is a form engine?

A form engine turns a data structure into a working form. You describe the fields, rules and flow once; the engine handles rendering, validation, conditional visibility, navigation and submission. The form becomes data you can version and review rather than components you maintain by hand.

Form engine vs. form library

The terms get used interchangeably, but they solve different halves of the problem.

A form library

Manages state, validation and submission for a form you have already built. You write the JSX for every field, wire each one to the library, and express conditional logic in your own component code.

You own the markup. The library owns the state.

A form engine

Takes a description of the form and renders it. Fields, validation rules, conditional visibility, multi-step navigation and submission all come from the same object, so adding a question is a data change rather than a code change.

You own the schema. The engine owns the rest.

Neither is better in the abstract. A library is the right tool for a login box. An engine earns its place when forms are numerous, change often, or are authored by someone who does not write React.

What that looks like

This is a complete, working form — four fields, one of which appears only when the budget answer warrants it. There is no component code, and the conditional rule is a property rather than a branch.

{
  "version": "1.0",
  "sections": [
    {
      "id": "contact",
      "title": "Get in touch",
      "questions": [
        { "id": "name",  "type": "short_text", "label": "Name", "required": true },
        { "id": "email", "type": "email",      "label": "Email", "required": true },
        {
          "id": "budget",
          "type": "single_select",
          "label": "Budget",
          "options": [
            { "value": "small", "label": "Under $5k" },
            { "value": "large", "label": "$5k+" }
          ]
        },
        {
          "id": "details",
          "type": "long_text",
          "label": "Tell us more",
          "showIf": { "field": "budget", "operator": "eq", "value": "large" }
        }
      ]
    }
  ]
}

When you need one

  • Many forms, one codebase. Intake, onboarding, surveys and applications share a renderer instead of each growing its own.
  • Forms that change without a deploy. A schema can live in a database row, so editing a form is editing data.
  • Non-developers authoring forms. JSON is reviewable by people who would not open a React file.
  • Logic that outgrows components. Conditional visibility, computed fields and cross-field validation become unreadable as nested JSX long before they become hard as data.
  • Forms you must audit. A schema diffs cleanly in review; a form spread across components does not.

When you do not. A single short form with no conditional logic is more code with an engine than without one. Reach for a library, or plain React.

What an engine has to do

A renderer that maps field types to components is not an engine. These are the parts that make it one.

Validate before it renders

A malformed schema should fail at load with a useful message, not halfway through a form a respondent is filling in.

Resolve conditions as a graph

Visibility and computed values depend on other answers, which depend on others. That is a dependency graph, and evaluating it in declaration order gets stale results.

Own navigation

If a question can be hidden, then step counts, progress and the meaning of “next” all change at runtime.

Separate delivery from rendering

Where a response goes is a deployment concern, not a form design one. The schema should not know your database.

FieldCraft

FieldCraft is a schema-driven form engine for React, MIT licensed and self-hosted. 18 input field types, 25 condition operators, 14 validator rules and 16 ready-made schemas. Responses go straight from the browser to an endpoint you control — there is no server of ours in the path.

Going deeper