This content originally appeared on DEV Community and was authored by Abhishek Ingle
Imagine you’re asked to build a product configuration form. At first glance, it sounds simple-pick a model, select a few options, and you’re done. But what if that product comes in _thousands_of possible combinations? Suddenly, your neat little dropdown turns into a nightmare of tangled logic and endless updates.
That’s the situation we found ourselves in. What began as a plain React form grew into a dynamic, rule-driven configurator that could scale gracefully and give users instant feedback. Here’s the story of how we got there.
Why Static Forms Fall Apart
Our first approach looked something like this:
<form>
<label>Model</label>
<select>
<option>Model-A</option>
<option>Model-B</option>
</select>
<button type="submit">Apply Configuration</button>
</form>
It worked for two options. But once complexity kicked in, the cracks showed:
- Hardcoding overload – every new choice meant editing frontend code.
- Validation lag – errors only appeared after hitting submit.
- Scattered rules – logic was split between frontend and backend.
- Scaling issues – hundreds of interdependent options were impossible to manage.
Clearly, this wasn’t sustainable.
The Pivot: Building Dynamically
We set four principles for the new system:
- Schema-driven forms – UI should generate itself from a JSON schema.
- Real-time validation – errors should appear as soon as a wrong option is selected.
- Centralized business logic – validation rules live in the backend, not duplicated in the frontend.
- Visual previews – users should see results immediately, even in 3D where possible.
The stack:
- React for the UI
- @rjsf/core (React JSONSchema Form) for schema-based form generation
- AJV for JSON Schema validation
- Node.js for enforcing business rules and integrating with PLM systems
- Three.js for interactive 3D previews
How It Fits Together
The frontend dynamically renders forms and handles simple checks. The backend enforces rules and returns either errors or a valid configuration. The preview then updates instantly.
JSON Schema: The Core
At the center is a schema like this:
{
"title": "Product Configuration",
"type": "object",
"properties": {
"model": { "type": "string", "enum": ["A", "B"] },
"color": { "type": "string", "enum": ["Red", "Blue", "Green"] },
"size": { "type": "string", "enum": ["Small", "Medium", "Large"] }
},
"required": ["model", "color"]
}
And the backend enforces rules cleanly:
app.post("/validate", (req, res) => {
const { model, color } = req.body;
if (model === "A" && color === "Green") {
return res.status(400).json({ error: "Model A does not support Green" });
}
res.json({ success: true });
});
No duplication, no guesswork.
Frontend Implementation
With RJSF and AJV, the form almost builds itself:
import Form from "@rjsf/core";
import validator from "@rjsf/validator-ajv8";
const schema = { /* schema as above */ };
const App = () => {
const handleSubmit = ({ formData }) => {
console.log("Submitted:", formData);
// Send to backend for validation
};
return (
<Formschema={schema}
validator={validator}
onSubmit={handleSubmit}
/>
);
};
export default App;
Custom UI tweaks and validation messages make it user-friendly while still fully dynamic.
The User Experience
Here’s what happens when someone configures a product:
- They select: Model A, Color Red, Size Medium.
- Local schema check passes.
- The UI displays the message instantly.
- Once valid, the live preview updates.
- They select: Model C, Color Red
-
API call flags an error:
{ "error": "Model A does not support Green" }
Result: a smooth, guided workflow with minimal frustration.
Why This Approach Works
- Scalable – handle thousands of options without rewriting the UI.
- Maintainable – rules live in one place, the backend.
- Cross-platform – the same schema can drive web, mobile, or desktop.
- User-friendly – instant validation and previews reduce trial-and-error.
Wrapping Up
We went from static, brittle forms to a flexible, schema-driven configurator that’s easier to maintain and far more enjoyable for users.
If your forms are drowning in hardcoded logic, it might be time to let schemas and centralized rules do the heavy lifting.
“Curious to try it out? Explore the project on GitHub Contributions and feedback welcome!”
Have you dealt with similar form chaos? How did you approach validation and scaling? Share your thoughts-I’d love to swap ideas.
This content originally appeared on DEV Community and was authored by Abhishek Ingle