Skip to content
bahtuiv0.18.8

<baht-form>

The L1 engine: one dumb controlled form. JSON in → UI out; emits baht-change / baht-validity. No buttons, no cross-field logic.

JSON in, form out

Build this JSON visually in the Builder, then copy it here.

<baht-form show-optional="true"></baht-form>

<script>
  const el = document.querySelector('baht-form');
  el.form = {
    "form_id": "contact",
    "form_name": "Contact",
    "fields": [
      {
        "order": 1,
        "type": "text",
        "key": "name",
        "label": "Name",
        "width": "1/2",
        "required": true,
        "value": ""
      },
      {
        "order": 2,
        "type": "text",
        "key": "email",
        "label": "Email",
        "width": "1/2",
        "required": true,
        "value": ""
      },
      {
        "order": 3,
        "type": "dropdown",
        "key": "topic",
        "label": "Topic",
        "width": "full",
        "options": [
          {
            "key": "bug",
            "label": "Bug report"
          },
          {
            "key": "feature",
            "label": "Feature request"
          }
        ],
        "value": null
      },
      {
        "order": 4,
        "type": "textarea",
        "key": "message",
        "label": "Message",
        "rows": 4,
        "value": ""
      }
    ]
  };
</script>

Read-only display

Same JSON, shown as values: option keys become labels, passwords are masked, missing answers read "Not provided". getData() still returns the full data.

<baht-form readonly="true"></baht-form>

<script>
  const el = document.querySelector('baht-form');
  el.form = {
    "form_id": "contact-ro",
    "form_name": "Contact",
    "fields": [
      {
        "order": 1,
        "type": "text",
        "key": "name",
        "label": "Name",
        "width": "1/2"
      },
      {
        "order": 2,
        "type": "email",
        "key": "email",
        "label": "Email",
        "width": "1/2"
      },
      {
        "order": 3,
        "type": "dropdown",
        "key": "topic",
        "label": "Topic",
        "options": [
          {
            "key": "bug",
            "label": "Bug report"
          },
          {
            "key": "feature",
            "label": "Feature request"
          }
        ]
      },
      {
        "order": 4,
        "type": "password",
        "key": "secret",
        "label": "API secret"
      },
      {
        "order": 5,
        "type": "textarea",
        "key": "message",
        "label": "Message"
      }
    ]
  };
  el.value = {
    "name": "Malee Srisuk",
    "email": "malee@example.com",
    "topic": "bug",
    "secret": "hunter2"
  };
</script>
NameTypeDefaultDescription
formJSFormDefinition—{ form_id, form_name, fields[] }
valueJSRecord<string, unknown>{}Controlled values
registryJSRegistry{}Custom formatters/validators
show-optionalbooleanfalseAppend a localized "(optional)" to every non-required label instead of relying on asterisks alone
optionsJSBahtFormOptions{}{ validateOn?: 'change'|'blur'|'submit', inputDebounce?: number }
fieldStatesJSRecord<string, DerivedFieldState>{}Per-field UI state from L2
viewstring | undefined | undefined—Name of a form.views entry: only that view's fields render and validate, but getData() still returns the full form
flagsJSFeatureFlags{}Feature-flag values (spec 01 §12). A field whose flag is off is not rendered, not validated and not in the payload
tabstring''Key of the open tab section; the first one showing when unset or gone.
readonlybooleanfalseRender every field as a display value (not a disabled form). Per-field readonly comes from the descriptor or a rule
  • getData()
  • setValue()
  • validate()
  • reset()
Method Returns Notes
getData() Record<string, unknown> the full payload: hidden / flag-off fields already cleared, computed values included
setValue(patch) void merge values in (prefill, a host-computed field); runs each key’s change scripts but emits no baht-change — the host already knows
validate() { valid, errors[] } run every validator now and show the errors; also emits baht-validity
reset() void drop every edit and value, clear errors and script state — back to the descriptors’ defaults
EventdetailDescription
baht-tab-changeCustomEventA tab of a tabbed layout was picked.
baht-validity{ valid, errors[] }Validity recomputed
baht-change{ form_name, key, value, data }Any field edited
nameCustomEvent