Plugins

Describe Form

describeForm() from @formkit/addons returns a plain, JSON-serializable description of a form: every field's name, address, type, label, validation rules, options, validity and error messages. It reads FormKit's node tree — not the DOM — so it works the same way in Vue and React, and it's ideal for:

  • AI agents and tools that need to know what a form wants before filling it in (pair it with node.input() and submitForm()).
  • Generated tests and fixtures.
  • Documentation and debugging of large or schema-driven forms.
Version

describeForm() is available in @formkit/addons 2.3.0 and later.

Installation

npm install @formkit/addons

describeForm is a plain function (not a plugin), so there is nothing to register — import it wherever you need it.

Usage

import { getNode } from '@formkit/core'
import { describeForm } from '@formkit/addons'

const form = getNode('signup')!
const description = describeForm(form)

For a form with an email, a password, and a select, the result looks like this:

{
  "name": "form_1",
  "address": "",
  "type": "form",
  "nodeType": "group",
  "required": false,
  "rules": [],
  "valid": false,
  "errors": [],
  "children": [
    {
      "name": "email",
      "address": "email",
      "type": "email",
      "nodeType": "input",
      "label": "Email",
      "required": true,
      "rules": [{ "name": "required", "args": [] }, { "name": "email", "args": [] }],
      "valid": false,
      "errors": ["Email is required."]
    },
    {
      "name": "plan",
      "address": "plan",
      "type": "select",
      "nodeType": "input",
      "label": "Plan",
      "required": false,
      "rules": [],
      "options": [
        { "label": "Free", "value": "free" },
        { "label": "Pro", "value": "pro" }
      ],
      "valid": true,
      "errors": []
    }
  ]
}

Driving a form

Every field includes an address relative to the node you described, so you can get back to the node with at():

const form = getNode('signup')!
for (const field of describeForm(form).children ?? []) {
  if (field.type === 'email') form.at(field.address)?.input('[email protected]')
}

Options

describeForm(node, {
  values: true,       // include current values (default: false)
  redact: ['email'],  // extra input types to redact (added to the defaults)
  errors: 'visible',  // only errors currently shown to the user (default: 'all')
})
  • values — Values are left out by default, so a description can be logged or sent to an agent without leaking user data. Set values: true to include them.
  • redact — Extra input types whose values are never included, even with values: true. They're added to the defaults — password and hidden (CSRF tokens and the like) are always redacted. Redacted fields are marked redacted: true. Pass redact: false to include everything.
  • errors — 'all' (default) includes every blocking validation and error message; 'visible' includes only messages the user can currently see, respecting each input's validation-visibility.

What's included

PropertyDescription
nameThe node's name (its key in the parent's value).
addressDot path from the described node, e.g. users.0.email. Empty for the described node itself.
typeThe input type (text, select, form, repeater, …).
nodeTypeinput, group, or list.
label, help, placeholderWhen set.
disabled, multiplePresent (and true) when set.
requiredWhether the required rule is applied.
rulesValidation rules with their arguments.
optionsOptions with their real values (option groups are flattened, with each option's group label; disabled options are flagged).
optionsLoadertrue when options are loaded by a function. The function is never called; options it has already loaded are included.
validtrue when neither the node nor its descendants have blocking messages.
errorsError message strings for the node.
valueThe current value, when values: true and not redacted.
childrenDescriptions of child nodes, for groups and lists.

The output is JSON-serializable: dates become ISO strings, regular expressions their source (e.g. "/^\\d+$/"), Maps and Sets arrays, and Files { name, size, type }. Functions and circular references are dropped, and other non-plain objects are copied as plain objects, so some detail can be lost.