In many real-world applications, especially form-heavy or wizard-style interfaces, validation isn’t just about individual fields — it’s about what happens across steps, when and how data should be validated, and how users move through a flow.
This is where most validation libraries fall short. They’re either too rigid, too form-specific, or not aware of user progression.
So I decided to solve it.
🎯 The Goal: Flow-Aware Validation Engine
The idea was simple but ambitious:
Build a schema-driven, flow-aware, and lifecycle-sensitive validation system — one that not only validates data, but understands where the user is in a flow, and what needs to be validated when.
This led to the creation of the following core building blocks in sd-is
v1.0.7:
🔧 Core Concepts Introduced
1. defineFlowSchema()
A declarative way to define a multi-step flow, where each step has:
- Its own schema
- Optional onEnter / onExit hooks for lifecycle-based validation
- Execution order control
const flow = defineFlowSchema({
steps: {
account: {
schema: defineSchema({ email: { type: 'string' }, password: { type: 'string' } }),
onEnter: (data) => { /* validate access */ },
onExit: (data) => { /* check password strength */ }
},
profile: {
schema: defineSchema({ name: { type: 'string' } })
}
},
order: ['account', 'profile']
});
2. validateStep()
& validateStepAsync()
Validate a specific step in the flow — respecting its schema, onEnter/onExit hooks, and returning a clean verdict.
const result = validateStep(flow, 'account', data); // sync
const result = await validateStepAsync(flow, 'account', data); // async
Async mode is particularly helpful for:
- API checks
- Debounced validations
- Async business logic (e.g., blocked email detection)
3. createFlow()
A full-blown flow controller built on top of defineFlowSchema
, managing:
- Step progression (
.proceed()
) - Navigation (
.back()
,.restart()
) - Debug logs
- State tracking
const flowEngine = createFlow(flow, { debug: true });
await flowEngine.proceed({ email: 'user@example.com', password: 'pass123' });
await flowEngine.proceed({ name: 'Tony Stark' });
flowEngine.back(); // go back a step
flowEngine.restart(); // restart the flow
console.log(flowEngine.getDebugLog());
🧪 What Makes It Different?
- ✅ Declarative: No spaghetti conditionals, no imperative mess
- ✅ Lifecycle-aware:
onEnter
andonExit
give precise control over transitions - ✅ Extendable: Schema validation can be synchronous or asynchronous
- ✅ Developer-first: Works great with logging, tracing, and testability
- ✅ Dependency-free: Zero external dependencies — just clean JS
💡 Use Cases
- Multi-step forms (onboarding, checkout, profile setup)
- Workflow engines
- Survey builders
- Any staged UI with dynamic rules
📦 Now on npm
npm install sd-is
- 📘 Docs & README
- 🧪 Fully tested — with
test.js
showcasing all capabilities
🛠️ What's Next?
The roadmap is exciting:
- ⚙️ Composable sub-flows
- 💡 Dynamic fix suggestions
- 🧩 Flow tracing with context
- 🔄
createFlowV
– a versioned, extensible flow runner for enterprise logic
🧠 Closing Thoughts
Validation shouldn't be dumb. It should understand context, user progression, and logic over time.
This evolution of sd-is
aims to make validation smarter, modular, and built for real-life flows, not just single-form fields.
If you're building form-heavy apps or complex flows — I’d love for you to give it a spin and share feedback!
→ GitHub: github.com/sandeepdara-sd/sd-is
→ NPM: sd-is
Let’s build better flows, together.
Top comments (0)