Skip to main content
Version: v2

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.

typeNotes
inputinputType: text email number tel url password date time datetime-local month week color checkbox (checkbox uses checkboxLabel)
textarea
select, multiSelect, radioGroup, checkboxGroupoptions: [{ 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
toggleon/off switch (validationType: "boolean")
addressaddress 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)
searchlive 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
countrySelectshowDialCode, modelValueKey (code by default, or name / dialCode), defaultValue
fileattributes: { 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
ratingconfig: { max }
scaleconfig: { 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)
phonea 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)
likertagree / 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
rankingpeople 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
sliderconfig: { min, max, step, unit }
heading, paragraph, dividercontent blocks (label / helpText, content, config.level)
columnsa row of columns, see Layout
pageBreaksplits 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
sectiona titled card around other fields (fields). config: style (card or plain), collapsible, startCollapsed. See App-like flows
repeatera group people can add several of (guests, rooms, meters…). The answer is a list of objects. See App-like flows
tabsswitch between groups of fields: tabs: [{ id, label, fields }], config.style (line or pills). The tab with an error opens by itself
modala dialog (pop-up form) that a button opens with the openModal action: label (title), fields, config.confirmLabel / cancelLabel / confirmActions. See Dialogs
buttona button that runs config.actions, see Buttons and actions
callouta 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, embedcontent 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 pagea 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)
signaturea 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