Skip to content

Events & Proxy

Events allow fields to react to user interactions. When a field changes, blurs, or receives focus, event handlers can mutate other fields' values and UI properties through a proxy system.

Defining Events

Use SchemaDefinition.events() to define field event handlers:

typescript
// domain/person/events.ts
import { PersonSchema } from './schema'

export const personEvents = PersonSchema.events({
  active: {
    change({ state, schema }) {
      schema.birthDate.hidden = !state.active
      schema.street.disabled = !state.active
      schema.city.disabled = !state.active
    },
  },
  email: {
    blur({ state, schema }) {
      if (!state.email.includes('@')) {
        schema.email.state = 'error'
      }
    },
  },
  name: {
    focus({ schema }) {
      schema.name.state = 'active'
    },
  },
})

Event Types

EventTrigger
changeField value changes
blurField loses focus
focusField receives focus

Event Context

Each event handler receives a context object:

PropertyTypeDescription
stateRecord<string, unknown>Proxied form state — mutations are tracked
schemaRecord<string, FieldProxy>Proxied field overrides — mutations are tracked

State Proxy

The state proxy wraps the current form values. Any mutations you make are tracked and applied after the handler returns:

typescript
change({ state }) {
  // Read current values
  const name = state.name

  // Mutate other fields
  state.fullName = `${state.firstName} ${state.lastName}`
  state.active = true
}

Under the hood, createStateProxy() creates a snapshot and tracks changes:

typescript
const { proxy, getChanges } = createStateProxy(currentState)
// After handler runs:
const changes = getChanges() // only the mutated keys

Schema Proxy

The schema proxy lets you dynamically override field UI properties:

typescript
change({ state, schema }) {
  schema.birthDate.hidden = !state.active    // show/hide
  schema.email.disabled = true               // enable/disable
  schema.name.width = 100                    // change width
  schema.name.state = 'error'                // set visual state
}

Available Proxy Properties

PropertyTypeDescription
hiddenbooleanShow or hide the field
disabledbooleanEnable or disable the field
widthnumberOverride field width
heightnumberOverride field height
statestringSet visual state (e.g., 'error', 'warning')

Using Events with useDataForm

Pass events to the hook:

typescript
const form = useDataForm({
  schema: PersonSchema.provide(),
  scope: Scope.add,
  events: personEvents,
  // ...
})

The hook automatically wires up events to onChange, onBlur, and onFocus callbacks on each field.

Best Practices

  • Keep events in a separate file (events.ts) from the schema definition
  • Use the state proxy for value mutations and the schema proxy for UI changes
  • Avoid async operations in events — use lifecycle hooks for async work

Released under the MIT License.