I used to think forms were just UI. You open a React component, add inputs, wire validation, and ship it. This works—until you scale.
When your product needs conditional fields, multi-tenant validation, or backend-driven workflows, "Just UI" breaks. Here is the architectural shift I took to solve this.
1. The Realization: Forms are Data, Not Screens
If a form is hardcoded in React, its definition is trapped. It’s coupled to deployment cycles and framework-specific logic.
The Shift: I moved to Schema-Driven Forms.
React stopped being the author and became the renderer. This made forms portable and dynamic, but it introduced a new problem: Schema Bloat.
2. The Trap: The "Mini-Programming Language" Schema
As requirements grew, my schemas started absorbing logic (if/then visibility, complex validation). The schema stopped being data and became a messy, hard-to-debug configuration layer.
I realized I was asking the wrong question. It wasn't about making forms dynamic; it was about Separation of Concerns.
3. The Breakthrough: The Registry Pattern
To keep the schema clean, I stopped implementing logic inside it. Instead, I used Registries.
- The Schema: Only references behavior (e.g., "visibilityRef": "isAdmin").
- The Registry: Implements the actual code logic.
// The logic lives in code, not the JSON
const adminOnly = (values) => values.role === 'admin';
registerVisibility('isAdmin', adminOnly);
4. The Architecture: Meet the Runtime
Once definition and behavior were separated, I needed an engine to orchestrate them. This is the "Brain" of the system.
The Three-Layer Model
Definition (JSON): The blueprint. No executable logic.
Runtime (The Engine): Manages state, evaluates registry rules, and triggers validation.
Renderer (UI): A thin layer (React, Vue, or Angular) that simply reflects the Runtime's state.
Why This Matters
By treating forms as architecture rather than UI:
Framework Agnostic: The core logic (Runtime) is stable across React, Vue, Angular and Vanilla JS.
Decoupled Logic: You can update validation or visibility rules without touching the UI components.
Maintainable Scale: The "definition" stays human-readable, while the "complexity" is modularized in the registry.
This philosophy is why I built Formitiva. It’s not just a library; it’s an honest separation of what a form is, how it acts, and how it looks.
Formitiva is a schema-driven form runtime engine built for teams that need forms to behave like portable system data, not hand-wired component trees. Describe intent in JSON, let the runtime handle execution, and keep renderers replaceable.
Now Formitiva supports 4 frameworks: React, Vue, Angular and Vanilla JS.
GitHub Link: https://github.com/Formitiva/formitiva-monorepo
Top comments (0)