Skip to content

@jayoncode/form-intelligence

Form Intelligence

Stop rebuilding form workflows in every app

Conditional fields, draft recovery, and submit races usually mean effects and flags everywhere. One headless createForm() owns validation, when() rules, autosave, and submit — your UI just binds.

SaaS checkout: conditional fields + draft autosave

import { createForm, when } from "@jayoncode/form-intelligence";

// Pain: enterprise fields, autosave, and submit guards
// usually mean 4 effects and a race on every keystroke.

createForm({
  target: "#checkout",
  schema: {
    plan: { required: true },
    seatCount: { required: true },
    companyName: { minLength: 2 },
    email: "email",
  },
  rules: [
    when("plan")
      .equals("enterprise")
      .show("seatCount", "companyName")
      .require("seatCount", "companyName"),
  ],
  workflow: {
    autosave: {
      enabled: true,
      debounceMs: 800,
      onSave: (values) => api.saveDraft(values),
    },
    draft: {
      enabled: true,
      storageKey: "checkout:draft",
    },
  },
  // Same store as form.subscribe() — fires once after create, then on every notify
  subscribe: (form) => {
    syncCheckoutChrome(form.state); // draft badge, plan label, …
  },
  async onSubmit(values) {
    await api.checkout(values); // isSubmitting + double-submit guard built in
  },
});
Read the overview

Why it stands out

when() instead of useEffect

Plan === enterprise? Show seats, require company, gate submit — declarative chains, not effect soup.

Drafts that survive refresh

Debounced autosave and local draft restore so long checkouts and applications do not evaporate.

Submit without race bugs

Async onSubmit with isSubmitting, duplicate-submit guard, cancel, and optional offline queue.

Keep your markup

Progressive enhance a native <form>, or bind() into React / Vue / your own inputs — same engine.

JOC — headless @jayoncode/* TypeScript libraries. Docs sync from package source via TypeDoc and sync scripts.