Form System
A reactive form engine for building intelligent, dynamic forms with complex dependencies and conditional behavior.
What is Dashforge Form System?
Understanding the core problem and solution
Dashforge Form System eliminates the manual wiring required for dynamic forms. No scattered useEffect hooks. No prop drilling. No manual re-render coordination. Instead, you declare what fields depend on each other, and the system handles all orchestration automatically.
It's built on top of React Hook Form, adding a reactive engine, declarative reactions, and runtime state management. Together, they handle validation, submission, async coordination, and field dependencies without boilerplate.
ℹ️
Core value: React Hook Form manages form state. Dashforge manages form behavior. You avoid manually connecting fields, watching for changes, and coordinating async operations.
The Problem
Why static forms aren't enough
Most form libraries handle static forms well: you define fields, add validation, submit the form. But real-world applications need dynamic behavior:
- Selecting "United States" should load a list of states for the next dropdown
- Checking "Ship to different address" should reveal additional fields
- Changing payment method should update available billing options
- Selecting a product category should filter available subcategories
Without a system to orchestrate these behaviors, you end up with:
- Scattered useEffect hooks throughout your form component
- Manual field state management alongside form state
- Complex event handlers that know too much about form structure
- Difficult-to-test spaghetti logic
⚠️
The core problem: Imperative orchestration of field dependencies quickly becomes unmaintainable as forms grow in complexity.
Core Features
Three key primitives
Dashforge Form System provides three key primitives to solve this problem:
1. Reactive Engine
A state management layer built on Valtio that tracks field values, visibility, and dependencies. When a field changes, the engine automatically evaluates dependent rules and updates affected fields.
2. Declarative Reactions
Define side effects as objects instead of imperative code. Specify what fields to watch, conditions to check, and effects to run. The system handles execution, async coordination, and stale response detection automatically.
3. Runtime Store
Separate storage for async metadata like loading states, dynamic options, and fetch errors. This keeps your form values clean while providing rich UI feedback during async operations.
Why Not Plain React Hook Form + UI Components?
What problem does Dashforge solve?
React Hook Form is excellent for form state and validation. But when fields need to interact—one field loading options based on another—you fall back to imperative code:
// Without Dashforge: Manual orchestration required
function AddressForm() {
const { watch, setValue } = useFormContext();
const [stateOptions, setStateOptions] = useState([]);
const [loading, setLoading] = useState(false);
const country = watch('country');
useEffect(() => {
if (!country) {
setStateOptions([]);
setValue('state', null);
return;
}
let cancelled = false;
setLoading(true);
fetchStates(country).then(states => {
if (!cancelled) {
setStateOptions(states);
setLoading(false);
}
});
return () => { cancelled = true; };
}, [country, setValue]);
return (
<>
<Select name="country" options={countries} />
<Select
name="state"
options={stateOptions}
loading={loading}
/>
</>
);
}With Dashforge, all orchestration is declarative:
// With Dashforge: Pure declaration
const reactions = [{
id: 'load-states',
watch: ['country'],
run: async (ctx) => {
const country = ctx.getValue('country');
if (!country) return;
const requestId = ctx.beginAsync('states');
ctx.setRuntime('state', { status: 'loading' });
const states = await fetchStates(country);
if (ctx.isLatest('states', requestId)) {
ctx.setRuntime('state', {
status: 'ready',
data: { options: states }
});
}
}
}];
<DashForm reactions={reactions}>
<Select name="country" options={countries} />
<Select name="state" optionsFromFieldData />
</DashForm>- No useEffect: Reactions replace imperative effect management
- No component state: Runtime store handles async metadata
- No manual cancellation: beginAsync/isLatest pattern built in
- No prop drilling: Fields read from runtime store directly
How It Works
The orchestration flow
Here's the high-level architecture of how the Form System orchestrates dynamic form behavior:
Step 1: User Input
User types or selects a value in a form field
Step 2: React Hook Form Processing
RHF validates the input, updates form state, tracks touched/dirty
Step 3: Engine Synchronization
FormEngineAdapter syncs the new value to the Reactive Engine
Step 4: Incremental Evaluation
Engine finds all reactions watching this field (O(1) lookup) and evaluates them
Step 5: Side Effects Execute
Reactions run: fetch data, update runtime state, modify other fields
Step 6: UI Updates
Components re-render with new state, showing updated options, visibility, or loading states
✓
The key insight: All this happens automatically. You declare the behaviors you want, and the system orchestrates the execution, handles async timing, prevents stale responses, and keeps everything synchronized.
Relationship to UI Components
How the system connects to inputs
The Form System is separate from the UI components. Individual input components like TextField, Select, and Autocomplete are documented in the UI Components section.
This Form System section focuses on:
- How to set up the form provider and engine
- How to define reactions and orchestrate field behavior
- How to handle dynamic forms with conditional fields
- How to structure complex forms for maintainability
- How the runtime store and async operations work
For documentation about specific input components (props, variants, examples), see the UI Components section.
Next Steps
Where to go from here
Continue exploring the Form System:
- Quick Start: Build your first dynamic form
- Reactions: Deep dive into declarative side effects
- Dynamic Forms: Learn conditional visibility and runtime options
- Patterns: Best practices for complex form architecture
- API Reference: Complete reference for form system APIs