Containers
Containers hold other elements. Most produce no data themselves; the exceptions are Object panel (one object built from its fields), Dynamic panel (an array of entries) and Tabs (whose active tab can be read in expressions).
Panel (panel)
A titled box that groups related fields.
| Property | What it does |
|---|---|
| Label / Description | Panel heading and sub-text. Hide header removes the heading row. |
| Background color | Panel surface color (e.g. #ffffff). Remove background disables it entirely. |
| Border style / color / width | solid, dashed, dotted, double; color like #d9dce3; thickness like 1px. Borderless removes the border. |
| Radius | Corner radius (e.g. 12px). |
| Shadow | CSS shadow (e.g. 0 8px 24px rgba(0,0,0,.12)). |
| Padding / Mobile padding | Inner spacing per breakpoint (e.g. 12px or 1rem). |
| Min height / Max height / Height / Fit content | Sizing; content past Max height scrolls (see Overflow). |
| Overflow | visible, auto, hidden, scroll, clip. |
| Opacity / Backdrop filter | Transparency and glass-style effects. |
| Use as page section | Turns the panel into a full width band for web pages: no border, content centred at a readable width. Its settings are listed below. |
| Content display | How children lay out: flex or grid. |
| Flex direction / Content gap / Content justify / Content align / Content wrap / Align content / Row & column gap | Flex composition of the children. |
| Grid columns / Grid rows / Grid auto rows | Grid composition, e.g. repeat(2, minmax(0, 1fr)), minmax(120px, auto). |
Page section
With Use as page section on (Design → Page section), a panel becomes the kind of block a web page is made of: a hero, a row of features, a call to action. It stretches the full width of its parent and centres its content inside.
| Property | What it does |
|---|---|
| Section colours | Light, or Dark (light text): everything inside switches to the dark palette, so headings, text, buttons and inputs stay readable on a dark background without any CSS. |
| Content width | How wide the content may get inside the band (default 1120px). Narrow it, e.g. 720px, for a sign-up box or a block of text. |
| Space above and below | Vertical breathing room. The default grows with the screen, from 48px on phones to 96px on wide screens. |
| Minimum height + Vertical position | For a hero band, e.g. 480px or 80vh, with the content at the top, middle or bottom. |
| Background color | The band's colour (the regular panel setting). |
| Background image + Image overlay | A picture behind the band, and a colour laid over it, e.g. rgba(0, 0, 0, 0.45), so text on a busy photo stays readable. |
Sections work in any render mode, but they shine with Canvas, where nothing else sits around them; see Web pages with Canvas.
A panel's visibleIf hides the whole group at once, which is usually cleaner than hiding fields one by one. Disabling or making a panel read-only cascades to children (children can opt out by turning off Inherit parent state).
Object panel (objectPanel)
A group of fields that saves its answers as one object named after the panel. Think of it as a Dynamic panel with exactly one entry: the same idea as SurveyJS's multipletext question, except that anything can go inside, not just text boxes. There is no Add or Remove button, the panel is always there once.
Drop an Object panel named address, put a few fields in it, and the data comes out like this:
"address": {
"city": "Vilnius",
"street": "Gedimino pr. 1",
"zip": "01103"
}The fields belong to the panel, so their names only have to be unique inside it. A Billing address and a Shipping address panel can both have a city field, and the data keeps them apart:
"billing": { "city": "Vilnius", "street": "Gedimino pr. 1" },
"shipping": { "city": "Kaunas" }Anything that stores a value works inside it: text and number inputs, selects, autocompletes, date pickers, file uploads, dynamic panels, and custom elements your developers registered. Layout containers in between do not change anything, so a Panel or Tabs inside the Object panel still put their fields into address. Another Object panel inside it adds one more level:
"address": {
"city": "Vilnius",
"geo": { "lat": 54.68, "lng": 25.28 }
}A few things to keep in mind:
- Refer to the fields by their full path from outside. In expressions, conditions, data source parameters and actions elsewhere in the form write
{address.city}. Inside the panel{panel.city}means the neighbouring field of the same panel, which is handy when two panels share field names. - Loading data works the same way. Pass
{ "address": { "city": "Kaunas" } }as the form data and the City field inside the panel showsKaunas. - Validation is per field. A required field inside the panel is checked like any other field; the panel itself has no validators.
- Keep out of data JSON on the Object panel leaves the whole object out of the submitted result.
- The properties are the Dynamic panel's without the row controls: title, header, colors, borders, padding, visibility, a data source that fills the whole object, and so on.
- Inside a Dynamic panel an Object panel adds its level to every entry:
items[0].address.city.
Use it when a group of answers belongs together and the backend expects it as one object: an address, a contact person, company details. If the user should be able to add several such groups, use a Dynamic panel instead, which stores an array.
Tabs (tabs) and Tabs Pro (tabsPro)
Horizontal tabs, each with its own rows of elements. Tabs Pro adds richer header styling.
| Property | What it does |
|---|---|
| Tabs | The tab list: value is the tab ID, label the name, visibleIf hides a tab conditionally. |
| Tabs data path | Load the tab list dynamically from data or a source response. |
| Active tab data path | Data path that stores/controls the active tab from outside. |
| Tabs position | Headers on top or at the sides (left/right). |
| Tabs variant | Visual style: underline, pills… |
| Full width tabs | Tab buttons fill the row in equal blocks. |
| Open first | First tab opens automatically. |
| Lazy content | Tab content renders only when the user opens it. |
| Tab template / Tab template ref | Fully custom tab header markup, inline or from the template library. |
The active tab is available to expressions:
{myTabs.selectedTab} → active tab name
{myTabs.selectedTabIndex} → active tab indexExample: show a hint only on the second tab with visibleIf: {myTabs.selectedTabIndex} == 1.
Accordion (accordion)
Vertically stacked collapsible sections. Good for optional/advanced settings that most users skip.
| Property | What it does |
|---|---|
| Items | The section list. |
| Open first | First section opens automatically. |
| Allow multiple | Several sections may stay open at once. |
| Item template / Item template ref | Custom section-header markup. |
Dynamic panel (dynamicPanel)
A repeatable group. You design the fields once; users add, remove, and reorder entries. The value is an array of objects:
"addresses": [
{ "city": "Vilnius", "street": "Gedimino pr. 1" },
{ "city": "Springfield", "street": "Freedom Ave 10" }
]| Property | What it does |
|---|---|
| Add row button text / Remove row button text | Button captions. |
| Disallow adding / deleting rows | Lock the entry count. |
| Disallow adding rows if (Logic) | While this condition is true, the add button is disabled: {rowCount} >= 3 or {orderClosed} == true. |
| Disallow deleting rows if (Logic) | Checked for every entry: an entry where it is true has no remove button, so {row.status} == "approved" keeps approved entries and lets the rest go. |
| Max rows | Upper limit. The add button disables once it is reached. |
| Confirm row deletion (+ title, message, button texts) | Ask before removing an entry. |
| Empty state text | Shown when the panel has no entries. |
Inside a dynamic panel, expressions get extra context:
| Token | Meaning |
|---|---|
panel.fieldName | A field in the same entry |
panel.index | This entry's position (0-based) |
parentIndex | Index of the surrounding repeater when nested |
Example, inside each address entry: visibleIf: panel.country == "LT".
Aggregate over all entries from outside the panel: sumInArray({orderLines}, "amount").
Dialog (dialog)
A modal window designed in the builder like a normal container. It stays hidden until opened by an action or condition:
- Add a Dialog element, give it a Name (e.g.
confirmDialog) and content. - On any button add an action: type
dialog, dialog nameconfirmDialog, operationopen(alsoclose,toggle).
| Property | What it does |
|---|---|
| Dialog mode | modal, draggable, or fullscreen. |
| Dialog width / height / max width / max height | Sizing (e.g. 720px, 90%, 90vh). |
| Title heading level | h1 to h3 for the dialog title. |
| Show close button | X in the header. |
| Close on backdrop | Clicking outside closes the dialog. |
| Initially open | Open by default when the view loads. |
| Open if | Expression that opens the dialog while true. |
| Open data path | A boolean data path that controls opening. Set it from actions or the host app. |
| Show trigger button | A built-in button that opens the dialog. |
| Trigger text / icon / icon position / icon only / variant / color / text color / width / mobile width / alignment | Full styling of that trigger button. |
Use dialogs for confirmations, quick sub-forms, and detail previews.
Splitter (splitter)
Two or more resizable side-by-side areas. Useful for list-detail layouts.
| Property | What it does |
|---|---|
| Orientation | horizontal or vertical. |
| Panels | The panel list: each value is the panel key and content identifier. |
| Show panel headers | A header for each panel. |
| Allow resize | Users drag the handle to resize. |
| Gutter size | Gap/handle size in pixels. |
| Min panel size | Minimum panel size as a percentage. |
| Stateful + State key | Persist panel sizes in localStorage under an optional custom key. |
Spacer (spacer) and Divider (divider)
Pure layout elements.
| Property | What it does |
|---|---|
| Axis | Which direction the element occupies (vertical/horizontal). |
| Height (Spacer) | The gap size. |
| Thickness (Divider) | Line thickness. |