Form System Overview | Dashforge-UI
DocsStarter Kits
v0.1.0-alpha

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

On This Page