Fields
Inputs accept config.prefix / config.suffix (fixed text next to the box, e.g. "m²"). Button and message texts can use {count:model} (number of items picked in a field) and {value:model} (its answer). Text inputs also accept attributes.autocomplete (e.g. given-name, email) for browser autofill, attributes.rows on textarea and attributes.step on number. Common properties: type, id, model (the key in the submitted data), label, helpText, tooltip (more help behind a small "?" after the label: shown on hover, keyboard focus and tap, read by screen readers), placeholder, defaultValue, visible, disabled, readonly, keyLocked (something outside the form, like the contract PDF, reads this answer by its model: the builder does not let it be renamed, nor a required field deleted), validationType, validations, logic.
type | Notes |
|---|---|
input | inputType: text email number tel url password date time datetime-local month week color checkbox (checkbox uses checkboxLabel) |
textarea | |
select, multiSelect, radioGroup, checkboxGroup | options: [{ label, value, group? }] (group lists options together in a dropdown). For radio / checkbox groups: config.optionColumns (1-4) and config.allowOther + config.otherLabel add an "Other…" option with a text box (the typed text is the answer). config.optionStyle: "cards" shows each choice as a card with a title and an optional option description, "chips" as small pills you switch on and off (a checkbox group as chips is a multi-pick); config.optionsFrom: { field, labelKey } takes the choices from the items of a repeating group (e.g. the units of this room); on a radio group config.autoAdvance goes to the next step as soon as an answer is picked. config.visibleOptions: N shows the first N options and a "Show more options" button for the rest (a picked option is always shown). See Rich options for badges, logos, links and help on each option |
toggle | on/off switch (validationType: "boolean") |
address | address search with short labels ("Street 5, 2200 City"). config.provider: osm (OpenStreetMap, worldwide, free, no key, light use), google (Places API New), mapbox, geoapify, dk (Danish official register, Dataforsyningen) or custom (your own source, as in search). Keyed providers take config.apiKey (it is visible in the page: restrict it to your domain). config.countries (ISO codes, e.g. ["dk"]) and config.city narrow the search, config.multiple allows several picks (use validationType: "array"), config.answer is what is saved: text (default), id or both ({ id, label }). Floors and doors are only available from providers that have them (e.g. dk) |
search | live search against your own endpoint, with removable chips when config.multiple. config.source: { url: "https://…?q={q}", resultsPath, labelKey, labelTemplate, valueKey, minChars, debounce, headers }. The answer is the valueKey of the pick (a list when multiple, so use validationType: "array"). The endpoint must return JSON and allow requests from your site (CORS). Step by step search (street → number → floor/door): add source.drill: { typeKey: "type", expandTypes: ["vejnavn", "adgangsadresse"] }. Results of those types open the next level when picked (the box is filled with their text and searched again; a result that equals the box text is the answer), other types are final. source.extraKey shows a small note next to a result, source.labelTemplate builds a short label from several fields |
countrySelect | showDialCode, modelValueKey (code by default, or name / dialCode), defaultValue |
file | attributes: { accept, multiple }. config.preview shows thumbnails of chosen images, config.compact replaces the big drop area with a small "add" button (good for photos), config.fileStyle: "block" makes that button a full-width dashed bar |
rating | config: { max } |
scale | config: { min, max, minLabel, maxLabel }. config.nps: true makes it a Net Promoter Score question: 0-10 kept on one line on phones, with a thin red / amber / green line for detractors, passives and promoters ("plain" drops the colours) |
phone | a country picker (flag and dial code, the re-country-select list) and the number. The answer is "+45 20123456" (country code, a space, the digits; a national leading 0 is dropped except for Italy). config.defaultCountry ("dk") is where it starts, otherwise the visitor's region / the form language's country. Pasting +46 70… picks the country. The phoneCountries rule also limits the picker. config.phoneStyle: inline (default: one box, the flag and dial code inside it) or separate (the picker next to the box) |
likert | agree / disagree style answers. The points are options ([{ label: "Strongly disagree", value: 1 }, …]). Without config.rows it is one question and the answer is a point; with config.rows: [{ label, value }] it is a table of statements and the answer is { [row value]: point } (on phones the rows become cards). config.showNumbers shows 1, 2, 3… above the points. Looks (the answer is always the point's number): config.style is dots (default), buttons (numbered boxes), emoji (options[].emoji, faces by default) or images (options[].image); config.colorMode: "gradient" tints the points red → green, options[].color sets one point's color, config.accent the color of the picked point; config.labels (one question) is all (default), ends or none. required means every statement is answered |
ranking | people put the options in order (click to place, drag or arrows to move). The answer is the list of option values, best first. config.rankLimit asks only for a top N. required means all options (or the top N) are placed |
slider | config: { min, max, step, unit } |
heading, paragraph, divider | content blocks (label / helpText, content, config.level) |
columns | a row of columns, see Layout |
pageBreak | splits the form into steps (with config.ending it starts the thank-you page instead). Its label is the title of the step that starts after it, helpText its description (the first step's are settings.firstStepTitle / firstStepDescription). It can have logic to skip the whole step |
section | a titled card around other fields (fields). config: style (card or plain), collapsible, startCollapsed. See App-like flows |
repeater | a group people can add several of (guests, rooms, meters…). The answer is a list of objects. See App-like flows |
tabs | switch between groups of fields: tabs: [{ id, label, fields }], config.style (line or pills). The tab with an error opens by itself |
modal | a dialog (pop-up form) that a button opens with the openModal action: label (title), fields, config.confirmLabel / cancelLabel / confirmActions. See Dialogs |
button | a button that runs config.actions, see Buttons and actions |
callout | a message box: label (title), content, config.tone (info success warning danger). Combine with logic to show it only when it applies paragraph and callout accept config.truncate to cut a long text short: { "by": "lines" | "characters", "limit": 5, "mode": "viewMore" | "tooltip" } (viewMore adds a "View more / View less" button, tooltip a "?" that shows the whole text). |
image, video, link, icon, embed | content blocks. image: config.src (https or an uploaded data URL), alt, caption, width (small / medium / full), align, link, rounded. video: config.url (YouTube (privacy-enhanced player), Vimeo, Loom, or an .mp4/.webm file), caption. link: label, config.url (http(s), mailto:, tel:), style (button / text), newTab. icon: config.emoji or config.icon (see BLOCK_ICONS), size, align, label / helpText under it. embed: config.url (https: a map, a booking calendar, a PDF), height |
| thank-you page | a pageBreak with config.ending: true: the blocks after it are shown after a successful send instead of the form (never as a step, no questions) |
signature | a box to sign in (finger, pen, mouse). The answer is a PNG data URL. config.height, config.hint. config.mode: "dialog" shows a grey box with a button (signLabel) that opens the signing pad in a dialog and then shows the signature |