Why mobx-react-form Is the Best Form Library You're Not Using
Source: Dev.to
If you build forms in React, you’ve probably tried Formik, React Hook Form, or final-form. They’re good. But if you deal with complex, deeply nested, multi-step forms — the kind that make you question your life choices — there’s a better tool.
mobx-react-form combines MobX reactivity with a powerful form state engine. Here’s why it deserves your attention.
- Nested Fields Without the Pain
Real forms aren’t flat. Take an invoice: you have a customer section, a shipping address, and a variable number of products, each with name, quantity, and price.
MRF handles this natively:
const fields = [
'customer.name',
'customer.email',
'shipping.address',
'shipping.city',
'shipping.zip',
'products',
'products[].name',
'products[].quantity',
'products[].unitPrice',
];
Enter fullscreen mode
Exit fullscreen mode
Each path becomes an observable field with its own validation, errors, and dirty tracking. No flattening. No normalization. The values serialize back to exactly the structure your API expects:
{
"customer": { "name": "...", "email": "..." },
"shipping": { "address": "...", "city": "...", "zip": "..." },
"products": [
{ "name": "Widget A", "quantity": 2, "unitPrice": 19.99 }
]
}
Enter fullscreen mode
Exit fullscreen mode
And with v6.15, errors bubble up automatically:
const form = new MobxReactForm({ fields }, {
options: { bubbleUpErrorMessages: true }
});
// When products[0].product is empty, this just works:
{form.error && }
Enter fullscreen mode
Exit fullscreen mode
2. Validation Plugins — Bring Your Own
MRF doesn’t lock you into one validator. It supports 6 validation plugins out of the box:
Plugin Package Style
DVR validatorjs Declarative rules (`‘required
VJF
Custom functions
{% raw %}(value) => [isValid, message]
ZOD zod Schema-based
YUP yup Schema-based
JOI joi Schema-based
SVK ajv Schema-based
Use DVR for simple fields and ZOD for complex cross-field validation — in the same form:
plugins() {
return {
dvr: dvr({ package: validatorjs }),
zod: zodPlugin({ package: z, schema: invoiceSchema }),
};
}
Enter fullscreen mode
Exit fullscreen mode
Define a Zod schema for your entire form and get both client-side validation and TypeScript types from one source:
const invoiceSchema = z.object({
customer: z.object({
name: z.string().min(2),
email: z.string().email(),
}),
products: z.array(z.object({
name: z.string().min(1),
quantity: z.number().min(1),
unitPrice: z.number().positive(),
})).min(1),
});
Enter fullscreen mode
Exit fullscreen mode
3. Full TypeScript Generics (v6.13)
If you’re on TypeScript, MRF now offers end-to-end type safety:
interface InvoiceForm {
customer: { name: string; email: string };
shipping: { address: string; city: string; zip: string };
products: Array;
}
const form = new MobxReactForm({ fields });
form.$('products[0]').$('name'); // Field — fully typed
form.values(); // InvoiceForm — fully typed
form.$('customer').$('name').set('Acme Corp'); // type-safe setter
Enter fullscreen mode
Exit fullscreen mode
Plus PathsOf for autocomplete:
form.$('ship') // → editor suggests: 'shipping.address' | 'shipping.city' | 'shipping.zip'
Enter fullscreen mode
Exit fullscreen mode
No more guessing field paths. No more runtime errors from typos.
- Dynamic & Array Fields
Need to add products dynamically? Remove a shipping address from a list? Built in.
// Add a product
form.$('products').add({
product: 'New Product',
quantity: 1,
unitPrice: 0,
});
// Remove the second product
form.$('products').del(1);
// Reorder (new in v6.14 with ArrayMap)
form.$('products').move(0, 2);
Enter fullscreen mode
Exit fullscreen mode
Arrays, nested arrays, dynamic field creation — MRF handles all of it with MobX reactivity. Each item gets its own validation lifecycle, dirty tracking, and error state.
- Composer — Multi-Form Orchestration
Have independent forms that need to submit together? The composer() function coordinates validation across forms:
const checkout = composer({ billing, shipping, payment });
checkout.validate().then(({ valid, errors, values }) => {
if (valid) {
submitOrder({
...values.billing,
shipping: values.shipping,
payment: values.payment,
});
} else {
// errors is keyed by form name: { billing: {...}, shipping: {...}, payment: {...} }
showValidationSummary(errors);
}
});
Enter fullscreen mode
Exit fullscreen mode
Perfect for checkout flows, multi-tab dashboards, and wizard-style UIs where each step is an independent form.
- UI Library Agnostic
MRF works with every major UI library — and doesn’t force you to pick one:
-
Material UI
-
Ant Design
-
React Aria
-
Headless UI
-
React Widgets
-
React-Select
-
Plain HTML
Each gets a thin binding layer. The form logic stays the same whether you render with MUI TextFields or raw “ elements.
// Works the same regardless of UI library
Save
Enter fullscreen mode
Exit fullscreen mode
Swap the Input component from MaterialTextField to AntdInput to SimpleInput — the form state doesn’t care.
- Built for Production, Maintained for Years
MRF has been powering production forms for 8+ years. It has 1.1k+ GitHub stars, and the latest releases (June 2026) brought the most requested features:
v6.15 — Error bubbling in nested forms
v6.14 — ArrayMap with predictable ordering and drag-and-drop support
v6.13 — Full TypeScript generics, strict null checks, path autocomplete
v6.12 — Custom validation type inference, YUP .ref() support
v6.11 — Full null values support
Each release was driven by real production needs, not hypothetical use cases.
The Bottom Line
Scenario MRF Alternatives
Simple login form ✅ Overkill but works ✅ Great fit
Deeply nested fields (invoice, order, profile) ✅ Native support ❌ Requires flattening
Dynamic arrays (add/remove/reorder) ✅ Built-in ❌ Manual state mgmt
Multi-form validation (checkout, wizard) ✅ Composer ❌ Custom orchestration
Validation plugins (DVR/ZOD/YUP/JOI) ✅ 7 plugins ❌ Usually 1-2
TypeScript generics + path autocomplete ✅ v6.13+ ❌ Limited
Error bubbling in nested forms ✅ v6.15+ ❌ Manual recursion
UI library flexibility ✅ Any library ✅ Any library
If you build forms beyond a login page — invoices, checkouts, multi-step registrations, admin panels with dynamic sections — give MRF a try. It handles the complexity so you don’t have to.
npm install --save mobx-react-form
Enter fullscreen mode
Exit fullscreen mode
