---
title: "Layout & Composition Widgets"
description: "Use combo charts, stat grids, dividers, and tabs to compose a dashboard, style any widget from its Style tab, and see how the grid reflows for tablets and phones and what each widget state means."
section: "Widgets"
canonical: "https://banksync.io/docs/widgets/dashboards-layout-widgets"
specs: ["dashboards"]
---

Most widgets show one thing: one chart, one number, one table. The widgets on this page do something different. They **compose**: a **combo chart** overlays several measures on one set of axes, a **stat grid** packs several KPIs into one block, a **divider** adds visual structure, and **tabs** group widgets so a single area can hold more than one view. Use them when a plain chart or KPI is not enough to tell the story.

> **Where to find them:** The combo chart (the Layered chart card) and the Divider are in the widget library like any other kind. Tabs is listed there too but marked Soon, so it cannot be added from the library yet, and the stat grid is not listed; today both arrive through an AI agent or a template. Divider and tabs each have their own inspector once they are on the canvas. See Adding widgets and the Dashboard templates page, both linked at the foot of this page.

![The dashboard editor's 12-column grid canvas with three placed widget cells, the first one selected with a highlight ring.](https://cdn.banksync.io/screenshots/dashboards/editor-canvas.65da014dfc08a336.png "Composition widgets share the same grid as every other widget: you place and arrange them like any cell.")

A combo chart, a stat grid, a section divider, and a tabs container all sit on this same 12-column grid alongside ordinary charts and KPIs, so you place, resize, and arrange them exactly like any other cell.

[![Layout widgets](https://cdn.banksync.io/videos/layout-widgets.poster.95194b7a6f96928f.png)](https://cdn.banksync.io/videos/layout-widgets.1ed9abfd8daf890d.mp4)

[Watch: Layout widgets](https://cdn.banksync.io/videos/layout-widgets.1ed9abfd8daf890d.mp4)

## Combo chart: overlay measures on one chart

A **combo chart** (the **Layered chart** card in the library) draws more than one kind of mark on the same horizontal axis. The classic example is **revenue bars with a margin-percent trend line on top**, where the two series use different scales. Instead of inventing a separate "bar-plus-line" chart kind, BankSync layers the marks: each layer is one mark (a line, bar, area, or scatter) plotted against a shared x axis.

### How layers work

- **One shared x axis.** Every layer is drawn against the same x field (for example, Month). You pick the x field once.
- **Each layer plots its own measures.** A layer carries one or more Y measures, and can have its own grouping (split into series) and color.
- **Marks can mix.** A bar layer and a line layer can sit on the same chart, so you get columns plus a trend line in one view.

### Two y scales: shared or independent

The most useful combo trick is putting two measures that live on different scales onto one chart, like dollars and percentages. Layered charts are the only charts that draw a second, right-hand axis, and only when you ask for one. That is controlled by the y-scale setting:

| Setting         | What it does                                                                                               | When to use it                                                                  |
| --------------- | ---------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- |
| **Shared**      | Every layer is measured against one common y axis                                                          | Both measures are in the same units (for example, two dollar amounts)           |
| **Independent** | Each layer reads the y axis its measure is assigned to: a **primary** (left) or **secondary** (right) axis | The classic dual axis: revenue dollars on the left, margin percent on the right |

Each Y measure is tagged as **primary** or **secondary**. With the independent setting, primary measures share the left axis and secondary measures share the right axis, so a small percentage and a large dollar figure each get a readable scale.

### Worked example: revenue bars and a margin-percent line

This is the canonical combo. With your data grouped by month:

1. Set the shared **x** axis to Month.
2. Add a **bar** layer plotting Revenue, assigned to the **primary** axis.
3. Add a **line** layer plotting Margin %, assigned to the **secondary** axis, with smoothing on.
4. Set the y scale to **Independent**.

You now read revenue as columns against the left axis and the margin trend as a smooth line against the right axis, in one chart.

> **Overlay a second source, like actual vs budget:** A layer can draw from a second, named dataset instead of the widget's main data. That is how an actual-versus-budget chart works: your actual-spend bars come from your transactions feed, and a budget line comes from a separate dataset, joined on the shared x (for example the month). The two series line up even though they came from different places.

The finished chart reads as revenue columns against the left axis with a smoothed margin-percent line tracking against the right axis, both in a single view.

## Stat grid: several KPIs in one block

A **stat grid** is a tidy row or grid of KPI cards built from one query result. Where a single [KPI](/docs/widgets/kpi-table-gauge) shows one headline number, a stat grid shows several side by side: think "this month's income, expenses, net, and savings rate" as four cards in one widget rather than four separate widgets you have to line up by hand.

- **Each cell is a KPI.** Every metric in the grid carries the same controls a standalone KPI has: a value, a summary, a comparison delta, a sparkline, formatting, and so on. (See [KPI, table & gauge widgets](/docs/widgets/kpi-table-gauge) for those controls.)

![The KPI inspector showing a sum of the amount field with the comparison delta-arrow enabled and an area sparkline turned on.](https://cdn.banksync.io/screenshots/dashboards/kpi-inspector.53ec7a776282ebb7.png "Each stat-grid cell reuses the standard KPI controls, like this single KPI's value, comparison, and sparkline.")

- **The grid handles the layout.** Set the number of **columns** (or let it flow automatically), the **gap** between cells, and whether to draw **dividers** between cells. A shared **variant** (card, plain, outlined) and **density** apply to every cell unless a cell overrides it, and you can add a **title** above the whole grid.

> **Stat grid is generally available:** A stat grid renders each metric as its own KPI card, including true previous-period comparisons. A fixed column count is a maximum: on a narrow card or a phone the cells wrap to the next row instead of squeezing. It is not in the widget library yet: it arrives through an AI agent or a template. Select it on the canvas to edit it: its inspector lists the metrics (add, choose, remove), edits the chosen one with the same controls as a KPI, and sets the columns, gap, dividers, caption and shared look.

A stat grid reads as a single block of evenly spaced KPI cards, for example a three-up row showing income, spending and net together.

## Text with live values and checklists

A text widget shows markdown. Bind it to data like any chart and it can also show numbers from that data: list them under `values`, then write `{{name}}` in the text.

```json
{
  "kind": "text",
  "allowEditor": false,
  "source": "You spent **{{spent}}** this month.\n\n- [{{has_rows}}] Connect a bank\n- [{{has_budget}}] Set a budget",
  "values": {
    "spent": {
      "field": "amount",
      "format": { "kind": "currency", "currency": "USD" }
    },
    "has_rows": { "aggregate": "count" },
    "has_budget": {
      "field": "budget",
      "dataset": "budgets",
      "aggregate": "max"
    }
  }
}
```

- Each value reads a `field` of the widget's rows, or of a named `dataset`. `aggregate` is `sum` by default (`avg`, `min`, `max`, `first`, `last`), and `count` counts rows.
- `format` writes the number as currency, percent and so on. Whole currency amounts drop the cents.
- A box written `[{{name}}]` becomes a tick (✅) when the value is above 0, `true` or non-empty text, and an empty box (☐) otherwise. A setup checklist follows the data with no manual ticking.
- With no rows yet a value shows `fallback`, a dash by default. A name not listed under `values` is left as written, so a typo is easy to spot.
- Names start with a letter and use letters, digits and underscores. A widget holds at most 20 values.
- Data never becomes formatting: characters such as `*`, `_` and `[` are removed from a value and line breaks become spaces, so a category name cannot add a link or a heading.

## Divider: line, space, or section header

A **divider** adds visual structure to a dashboard without showing any data. It is the simplest composition widget and renders immediately. It has three sub-kinds you switch between in its inspector:

| Sub-kind   | What it draws                            | Controls                                                          |
| ---------- | ---------------------------------------- | ----------------------------------------------------------------- |
| **Line**   | A horizontal rule across the cell        | Color, thickness, and style (solid, dashed, dotted)               |
| **Header** | A section title (for example "Cashflow") | Text, alignment (left/center/right), font size, weight, and color |
| **Space**  | Blank breathing room                     | Height in pixels                                                  |

Switching the sub-kind only shows the controls that apply to it, so the Header controls appear only when the sub-kind is Header, and so on. A divider spans the full width of the dashboard, which makes it ideal for breaking a long dashboard into labelled sections.

> **Group a long dashboard into sections:** 'Drop a Header divider above each block of widgets ("Income", "Spending", "Goals") and a Line or Space divider between sections. A reader scanning a tall dashboard then has clear signposts instead of one undifferentiated wall of charts.'

In the divider inspector you pick the sub-kind first, and the panel then shows only that sub-kind's controls: choosing Header, for example, reveals the text, alignment, font-size, weight, and color fields.

## Tabs: more than one view in one area

A **tabs** widget is a container that groups other widgets behind a tab strip, so one area of the dashboard can hold several views the reader switches between. Use it when you have, say, a "By month" chart and a "By category" chart that answer related questions but you do not want both on screen at once.

### Building a tabs widget

You configure the tabs themselves in the tabs inspector:

**Set up tabs**

1. **Add and name tabs** — Add a tab, give it a clear label, and optionally an icon. Reorder or remove
   tabs from the same panel.
2. **Pick the default tab** — Choose which tab is active when the dashboard first loads. If you do not,
   the first tab wins.
3. **Style the strip** — In Appearance, set the strip's position (top, bottom, left, right), its
   style (underline, pills, segments, enclosed), alignment, colors, and whether
   switching tabs animates.
4. **Add a badge (optional)** — A tab can show a small badge value next to its label, such as a count.

### Putting widgets into a tab

The tab inspector sets up the tabs; **which widgets live in each tab is decided on the canvas**, by dragging widgets into the active tab rather than in the inspector. A tab simply references the widgets assigned to it, so the same widget is never duplicated.

> **Tab content placement is still landing:** 'In the current build the tab strip itself renders and is interactive: you can switch tabs, and your position, style, colors, icons, and badges all show. The content area for the active tab shows a "Drop widgets into \<tab> from the canvas" prompt, because dragging widgets into a tab on the canvas is still being wired up. Use tabs to plan structure now; full content placement follows.'

On the canvas a configured tabs widget shows its interactive strip (for example three pill-style tabs, one carrying a count badge) above a content area that, for now, displays the "Drop widgets into this tab from the canvas" prompt.

## Style any widget: the Style tab

Every widget, composition or not, has a **Style** tab in its inspector. From top to bottom:

| Section                 | Controls                                                                                                                                                                  |
| ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Size**                | **S**, **M**, **L**, **Full** presets, plus **Width** and **Height** steppers in grid cells. Each kind has a minimum, shown in the label (for example "Width · 3 to 12"). |
| **Border**              | **Visible** or **Hidden**.                                                                                                                                                |
| **Header**              | **Visible** or **Hidden** (the title strip).                                                                                                                              |
| **Card**                | See below.                                                                                                                                                                |
| **On phones**           | **Show on phones** and **Phone height (rows)**. See below.                                                                                                                |
| **This dashboard only** | For a widget pinned to this dashboard: **Title override**, a **Border** and **Header** override, and **Lock position**. The widget's other placements are unchanged.      |

The **Card** section sets how the widget's card looks:

- **Show description**: shows the widget's description as a one-line subtitle under the title (hover to read all of it). Add the description on the Info tab first. Turn it off to keep the description without showing it.
- **Show icon**: the small icon beside the title: the one you picked, or else the kind's own drawn icon. KPIs hide it by default; other widgets show it.
- **Accent colour**: a hex color that replaces the first palette color for this widget. **Clear** goes back to the palette.
- **Surface**: **Card** (the plain card), **Tinted** (a light wash of the accent color), or **Clear** (no fill; sits on the page).
- **Padding**: **Roomy**, **Tight**, or **None**. Until you pick one, it follows the dashboard's **Density**; **Follow dashboard density** resets it.
- **Title alignment**: **Left** or **Centre**.
- **Drawing style** (charts only): **Dashboard** follows the dashboard's style; **Clean**, **Sketch**, or **Doodle** overrides it for this chart. See [Theming](/docs/dashboards/dashboards-theming#drawing-style-clean-sketch-or-doodle).

Size changes from the steppers go on the undo stack like a drag, and a locked widget cannot be resized until it is unlocked.

## Phones, tablets, and wide screens

You always build a dashboard on a 12-column grid. When someone views it, the grid follows the width of the dashboard itself (not the whole browser window), so a dashboard in a narrow pane or beside an open panel reflows too:

| Dashboard width | Layout                                                                                                         |
| --------------- | -------------------------------------------------------------------------------------------------------------- |
| 900px and wider | The 12-column grid, exactly as you built it.                                                                   |
| 600px to 899px  | 6 columns. Positions and widths are halved, rounding up, so a 3-column KPI keeps a readable width.             |
| Under 600px     | A phone stack. Widgets run top to bottom, left to right, full width. Two KPIs next to each other share a line. |

The tablet and phone layouts are worked out from your 12-column layout each time; they are never saved separately, so there is only one layout to maintain. Editing always happens on the 12-column grid. On a phone the dashboard opens for reading; the only editing there is finishing the setup of a widget that has no data yet.

### Heights on a phone

A height that suits a wide card is often wrong on a phone, so each kind gets a phone height of its own:

| Widget                                          | Rows on a phone                              |
| ----------------------------------------------- | -------------------------------------------- |
| KPI                                             | 2                                            |
| Gauge, meter, progress, sparkline               | 3                                            |
| Any other chart                                 | 4                                            |
| Table, list, board, calendar, timeline, gallery | Its desktop height, at least 4 and at most 7 |
| Text, image, embed, tabs, form, custom widget   | Its desktop height, at least 2 and at most 6 |
| Divider                                         | 1                                            |

To change this for one widget, set **Phone height (rows)** in its **On phones** section (1 to 12). **Automatic** goes back to the default, and the hint shows what that default is for the kind. To leave a widget off phones altogether, turn off **Show on phones**. It still shows on tablets and desktop. Some native BankSync widgets grow to fit their content on phones; for those the section says so instead of offering a height.

## What a widget shows when it has nothing to draw

A widget always says what state it is in, so a failure never looks like an empty result:

| State          | What you see                                                                                                                                    |
| -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| Loading        | A pulsing outline in the widget's shape (bars, a ring, rows, or a number) until the data arrives.                                               |
| Empty          | A faint hand-drawn outline and a message, for example "No data yet — the source may not have synced" or "No rows match the current filters".    |
| Error          | "Couldn't load this widget", **Retry**, and a **Details** disclosure. A missing or changed source also offers **Change source** and **Remove**. |
| Needs a source | "No data source connected yet" and **Choose data**, which opens the widget's Data tab.                                                          |
| Needs setup    | What is missing, for example "Choose a category and a value". Open the inspector to finish it.                                                  |
| No access      | A lock and "You don't have access to this data".                                                                                                |
| Too small      | "Make this widget bigger". Drag it larger or raise its **Width** and **Height**.                                                                |
| Needs history  | A chart with `minHistory` keeps its box and says how many periods it still needs. A KPI comparison shows a dash and "needs 2 months".           |

On a very short widget the same states collapse to a single line, so a one-row KPI still reads cleanly. See [Troubleshooting](/docs/dashboards/dashboards-troubleshooting) for how to clear each one.

## Which one do I reach for?

| Goal                                                                 | Use                                          |
| -------------------------------------------------------------------- | -------------------------------------------- |
| Two measures, one on each scale (dollars and a percent) on one chart | **Combo chart** with the independent y scale |
| Several headline numbers grouped together                            | **Stat grid**                                |
| A section title or visual break in a long dashboard                  | **Divider** (header / line / space)          |
| Two related views in one area, switched by the reader                | **Tabs**                                     |

## Related guides

- [Dashboards & widgets overview](/docs/dashboards/dashboards-overview): how the canvas, library, inspector, and filters fit together.
- [Adding widgets](/docs/widgets/adding-widgets): the everyday ways to put a widget on the canvas.
- [Binding data](/docs/widgets/binding-data): the Group by, Value, and series controls a combo chart's layers share with every chart.
- [The chart kind catalog](/docs/widgets/chart-kinds): the single-mark chart kinds a combo overlays.
- [KPI, table & gauge widgets](/docs/widgets/kpi-table-gauge): the KPI controls each stat-grid cell reuses.
- [Theming](/docs/dashboards/dashboards-theming): the dashboard-wide drawing style, palette, density, and frame that each widget's Style tab can override.
- [Dashboard templates](/docs/dashboards/dashboard-templates): templates are the easiest way to get a combo, stat grid, or tabs onto a dashboard today.

[Publish and share your dashboard](/docs/dashboards/publishing-and-sharing)
