Form builder canvas
The editor is three regions around one FormDefinition (see form-definition):
┌────────────┬──────────────────────────┬────────────────┐
│ Palette │ Canvas │ Inspector │
│ add field │ rows, steps, selection │ selected field│
└────────────┴──────────────────────────┴────────────────┘
The host's component library supplies the chrome. This skill is the behavior. Any drag-and-drop library is fine; the gestures below are the contract.
Palette
Render one item per field manifest, in catalog order. The three-letter tag
is the glyph — skip an icon set.
Adding a field (click or drag onto the canvas) inserts a new field built from
that type's defaults, with a name unique among the form's existing keys. On
a multi-step form the new field lands in step 1; the author drags it from there.
Canvas
Draw fields as cards in the rows from the width packer, in array order. The
canvas is a projection of the flat fields array, so a drop writes back an
index into that array. Use each row's startIndex to turn a row-relative drop
into that index.
Gestures:
- Reorder within a row or across rows.
- Move between steps by dropping on another step's header.
- Drop on an empty canvas. The empty state is a real drop target, with a short line of copy pointing at the palette.
One field is selected. Delete removes it. Duplicate inserts a copy after it
with a fresh id and a unique name.
Inspector
The inspector edits the selected field and shows only what its manifest allows:
- label, and the submission key (editable; once edited, label changes leave it)
- placeholder, when
supportsPlaceholder - required, when
supportsRequired - options editor, when
hasOptions— add, remove, reorder lines - width: Full, Half, Third, Quarter
- step assignment, when the form has more than one step
- conditional rule, aimed at another field on this form
Form-level settings (heading, button label, success message, destination, spam protection) live in a form settings surface, separate from the field inspector, so selecting a field never hides them behind a mode switch that is hard to find. A header control is enough.
Steps
Multi-step is a setting on the form. Off, the canvas is one list. On, fields group into step containers:
- The header title is editable inline. Default titles are "Step one", "Step
two", and so on, stored as the
stepsarray. - Add inserts a step after the current one and renumbers.
- Delete is refused when it is the only step. Otherwise its fields move to the previous step. Confirm when the step still has fields.
- Collapse is local UI state and is not persisted.
- The submit button renders on the last step only. Earlier steps navigate.
Starter forms
Ship two or three starters as plain FormDefinition values — a one-line email
signup (email at 75% width beside the button's row), a contact form (name,
email, message), and a two-step contact form. Applying one replaces the field
list. After that it is an ordinary form; nothing stays linked to the starter.
Save
Track dirty state against the last loaded document and save the whole field
list plus step titles in one write. A banner names unsaved edits. Warnings from
form-definition render inline and do not block the save; publishing a form
with no-fields or no-submit-target is the point to insist.
The canvas hands the same document to form-preview. It does not draw a
lookalike of the published form inside the card.