react-data-form
Introduction
What the library does, and what it deliberately does not.
react-data-form takes an object describing a form — its fields, their labels, what happens on submit — and renders it. It holds the state, runs the validators, and puts the violations your API returns back on the fields that caused them.
A first form#
Two imports and one object. useForm builds the form and owns its state; FormElement renders the whole thing — header, fields, errors and submit button.
import { DatePickerInputController, FormElement, useForm } from "react-data-form"
function ProfileForm() {
const formContext = useForm({
form: {
label: { title: "My profile" },
inputs: {
firstName: { label: "First name", required: true },
email: { type: "email", label: "Email" },
birthDate: { label: "Born on", controller: DatePickerInputController },
},
onSubmit: (data) => api.patch("/me", data),
},
})
return <FormElement {...formContext} />
}The form above, running
The payload beside the form is what onSubmit receives. That is the whole contract: a description goes in, a plain object comes out.
Why data, not JSX#
A form written as JSX can only be read by React. A form written as data can be stored in a database, merged with another one, filtered by permission, or generated from an OpenAPI schema — and only then handed to React.
// Nothing about this is JSX, so it can be stored, transformed,
// merged with another description, or generated from an API schema.
const form = {
inputs: {
title: { label: "Title", required: true },
status: { label: "Status", controller: SelectInputController, valueOptions },
},
}This is also what lets react-resource-view build a table, an edit screen and a filter bar from the same object: the description is the single source, and every screen is a reading of it.
One field, one controller
{ formInput, onChange } and nothing else. Forty-odd ship with the package, and writing your own takes about ten lines.What it does not do#
The library is deliberately narrow. It has no opinion on where your data comes from or where it goes:
- No HTTP client.
onSubmitreceives an object; what you do with it is yours. - No schema library. A field's
validatoris a function that throws. Zod errors are understood, but nothing forces you to use Zod. - No router. A form is a component, not a page.
- No visual identity. The components use Tailwind classes backed by the shadcn theme variables, so they take your palette rather than imposing one.