
Webiny Form Model
Building forms with the FormModel system, field types, renderers, layout, validation...
Install
npx skills add webiny/webiny-js --skill webiny-form-model -g -a claude-code -y- Repository
- webiny/webiny-js8.1k
- Category
- Engineering
- Updated
- 5d ago
- License
- See repository
- Context cost
- Mediumabout 3,000 tokens
- Runs scripts
- No, instructions only
What it does
Building forms with the FormModel system, field types, renderers, layout, validation, conditional rules, computed fields, and dynamic zones. Use this skill when the developer needs to define form fields with the builder API, choose renderers, build layouts with tabs/rows/separators, add validation (Zod or imperative), use conditional visibility/disable rules, create computed fields, or work with object fields and templates (dynamic zones).
Form Model
TL;DR
The Form Model is Webiny's declarative form system. Define fields with a fluent builder API (fields.text(), fields.datetime(), etc.), arrange them with a layout builder (layout.row(), layout.tabs(), etc.), and validate with Zod schemas or imperative rules. Fields support conditional visibility, computed values, reactive context from other fields (.context()), and deeply nested object/list structures with templates (dynamic zones).
Field Types
All fields are created via the fields registry callback. Each builder method returns a chainable builder.
Text
fields.text();
Default renderer: textInput. Value: string | null.
fields.text().label("Title").placeholder("Enter title").required("Title is required")
fields.text().renderer("textarea", { rows: 4 })
fields.text().list().renderer("tags").defaultValue([])
fields.text().list().renderer("textInputs", { addItemLabel: "Add text" })
fields.text().list().renderer("textareas", { addItemLabel: "Add description" })
fields.text().renderer("codeEditor", { language: "html", height: 300 })
fields.text().options([
{ label: "Option A", value: "a" },
{ label: "Option B", value: "b" }
]) // auto-switches to "select" renderer
fields.text().options([...]).renderer("radioButtons")
fields.text().list().options([...]).renderer("checkboxes")
// Dynamic options, callback receives { field, form }, re-evaluated reactively
fields.text().options(({ form }) => {
const type = form.field("general.type").getValue();
return getOptionsForType(type);
})
Number
fields.number();
Default renderer: numberInput. Value: number | null. Auto-normalizes to number.
fields.number().label("Count").placeholder("0").required();
fields.number().list().renderer("numberInputs", { addItemLabel: "Add number" });
fields.number().options([
{ label: "Tier 1", value: 100 },
{ label: "Tier 2", value: 200 }
]);
