Skip to content

Repository files navigation

driven-form

npm license

Headless React form engine — your backend defines the form, your frontend just renders it.

Conditional fields, validation, calculated values and repeaters live in a JSON schema your backend controls. Change a form without a frontend deploy.

{
  "name": "companyName",
  "type": "text",
  "label": "Company name",
  "show": "%hasCompany% == 'Yes'",
  "required": "%hasCompany% == 'Yes'"
}

That's the entire "add a conditional field" ticket. No frontend PR.

Playground Edit a schema, watch the form change. Nothing to install.
Quickstart Working in about five minutes.
Showcase Seven real forms — conditionals, repeaters, async checks, live design swapping.
How it compares An honest look at when to use something else instead.

Install

npm install driven-form
import { DrivenForm, createFieldRegistry } from 'driven-form/react'

// Write each field component once. The engine wires up value, error,
// show/required/disabled, and onChange/onBlur for you.
const registry = createFieldRegistry()
registry.register('text', TextInput)

<DrivenForm
  schema={schemaFromYourApi}
  fieldRegistry={registry}
  onSave={({ data }) => api.submit(data)}
>
  {({ handleContinue }) => <button onClick={handleContinue}>Submit</button>}
</DrivenForm>

Everything after that — conditionals, cross-field validation, calculated values, async checks, repeaters — is a schema change, not a code change.

What you get

  • The library owns logic and state. You own every pixel. It ships no UI at all, so a TextInput you write on day one never needs touching again.
  • A small expression language driving show, required, disabled and calculateValue — evaluated by a sandboxed AST interpreter, never eval().
  • Calculated values that settle in one write, through a dependency graph built when the schema is parsed. A four-deep chain costs one render pass.
  • Repeaters as a first-class field, with per-row scoped validation, row expressions, and cross-row aggregates like sum(%rows%, 'amount').
  • A render-count contract, enforced by tests. A field re-renders only when its own value, its own error, or a declared dependency changes — you can watch it happen in the playground's Renders tab.
  • Tree-shakable by construction. Repeater support only enters your bundle if you import it, guarded by a check that fails the build otherwise.

Try it locally

git clone https://github.com/vineetpjp/driven-form
cd driven-form/examples/plain-html   # smallest complete integration
npm install && npm run dev

examples/basic is the kitchen sink: conditional sections, async validation, a cap table, cross-row aggregates and a 95-field performance page.

Status

Pre-1.0. The core engine, expression language, registry, validation, lazy fields, repeaters and cross-row aggregates are implemented and covered by 324 tests. The API may still shift before a 1.0 tag — see V2-TODO.md for what's next and CHANGELOG.md for what's changed.

MIT

About

Headless React form engine - your backend defines the form, your frontend just renders it.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages