# Containers

> Panel, Object panel, Tabs, Accordion, Dynamic panel, Dialog, Splitter, Spacer, and Divider, with full property tables.

Source: https://ngxviewbuilder.io/creators/elements/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](https://ngxviewbuilder.io/creators/layout#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](https://ngxviewbuilder.io/creators/elements/containers#dynamic-panel-dynamicpanel) 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:

```json
"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:

```json
"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:

```json
"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 shows `Kaunas`.
- **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](https://ngxviewbuilder.io/creators/elements/containers#dynamic-panel-dynamicpanel) 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](https://ngxviewbuilder.io/creators/templates). |

The active tab is available to expressions:

```text
{myTabs.selectedTab}          → active tab name
{myTabs.selectedTabIndex}     → active tab index
```

Example: 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**:

```json
"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:

1. Add a Dialog element, give it a *Name* (e.g. `confirmDialog`) and content.
2. On any button add an action: type `dialog`, dialog name `confirmDialog`, operation `open` (also `close`, `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. |
