Overview
The four ideas that make Easy Forms work — the schema, the store, the renderer registry, and the dependency engine.
Easy Forms has a small number of moving parts. Once these click, the whole library makes sense.
The pipeline
FormSchema ──▶ <Form> ──▶ FormStore ──▶ <Field> per question ──▶ Renderer (from registry)
│ ▲ │
│ └──────────── values / errors ──────────┘
└──▶ Dependency engine (props / value / reset)
└──▶ Plugins (onInit / onChange / onSubmit / onDestroy)- Schema — a typed description of the form as data. Read more
- Store — a custom external store (via
useSyncExternalStore) holding every field's value, error, and touched/dirty state, with topic-based per-field subscriptions. Read more - Renderer registry — a map from a control name (
text,dropdown, …) to a React component. The shadcn registry is the default; it is fully swappable. Read more - Dependency engine — evaluates the three categorical dependency kinds to update props, derive values, and reset fields. Read more
What you write vs. what the library owns
You write
The schema, validators, dependency rules, your onSubmit handler, and (optionally) custom renderers.
The library owns
State, rendering, validation execution, conditional logic, dirty/touched tracking, wizard navigation, and submission flow.
Mount order matters
<Field> registers itself with the store in a useEffect. <Form> attaches the
dependency engine and plugins in its own useEffect, which runs after all child
field effects — so the engine sees every registered field on its first run. You never
manage this yourself; it is worth knowing when reasoning about timing.
Continue with The schema.