---
title: Tile types
description: All eighteen Dashies tile types, the bindings each one requires, its ceilings, and what it does instead of drawing a misleading picture.
updated: 2026-08-05
---

A tile is one entry in the spec's `tiles` array. Every tile carries a `type`, and
that type decides which other fields are required. A build guard reads the
published schema and fails this site when a tile type exists with no row here or
when a row's required bindings disagree with the schema.

Every tile also accepts `w` (an integer 1 to 12, its width in grid columns). All
of them except `text` and `custom` accept `dataset`, which routes the tile at a
named dataset; `custom` names its datasets with `reads` instead, and `text` reads
none.

## The eighteen types

| Type | Required bindings | What it draws |
|---|---|---|
| `kpi` | `measure` | One number, with an optional drill-through. |
| `chart` | `chart`, `x` | Bar, horizontal bar, line or area. |
| `table` | none | The dataset as a table. |
| `matrix` | `rows`, `cols`, `measure` | A cross-tab with real subtotals. |
| `heatmap` | `rows`, `cols`, `measure` | The matrix, colour-scaled. |
| `scatter` | `point`, `x_measure`, `y_measure` | Two measures against each other, one point per member. |
| `treemap` | `x`, `measure` | Part-of-whole by rectangle area. |
| `waterfall` | `x`, `measure` | A total broken into the contributions that make it up. |
| `funnel` | `x`, `measure`, `stages` | Declared stages in declared order, with step conversion. |
| `drilldown` | `levels`, `measure` | A breakdown you can descend, one level per click. |
| `stacked` | `x`, `series`, `measure` | Stacked bars or areas, normal or 100 percent. |
| `combo` | `x`, `measure`, `measure2` | Two measures on two axes. |
| `pie` | `x`, `measure` | Share of a whole. |
| `donut` | `x`, `measure` | The same, with the total in the hole. |
| `gauge` | `measure`, `max` | One measure against a declared scale. |
| `filter` | `dimension` | A slicer over one dimension. |
| `text` | `body` | Markdown prose. Reads no data. |
| `custom` | `reads` | Your own HTML, your own JavaScript, or both. |

`pie` and `donut` are two values of one schema shape, which is why they take the
same bindings.

## Optional bindings, by tile

| Type | Also accepts |
|---|---|
| `kpi` | `drill`, `title`, `note`, `intent` |
| `chart` | `measure` or `measures` (2 to 4), `series`, `sort`, `limit` (1 to 100), `height` (120 to 800), `cross_filter`, `viewer`, `drill` |
| `table` | `columns` (1 to 12), `group`, `sort`, `limit` (1 to 500), `viewer`, `drill` |
| `matrix` | `subtotals`, `limit` (1 to 1,000), `color` |
| `heatmap` | `subtotals`, `limit` (1 to 1,000), `color` |
| `scatter` | `limit` (1 to 2,000), `height`, `drill` |
| `treemap` | `limit` (1 to 200), `height`, `drill` |
| `waterfall` | `limit` (1 to 200), `height`, `drill` |
| `funnel` | `height`, `drill` |
| `drilldown` | `top_n` (1 to 1,000), `other`, `total` |
| `stacked` | `stack`, `chart`, `limit` (1 to 400), `height` |
| `combo` | `chart`, `chart2`, `axis_sync`, `limit` (1 to 400), `height` |
| `pie`, `donut` | `height` |
| `gauge` | `min`, `target`, `height` |
| `filter` | `label`, `multi`, `range` |
| `text` | nothing beyond `body`, `intent` and `w` |
| `custom` | `html`, `js`, `title`, `note` |

`title` and `note` are accepted on every tile except `filter` and `text`.
`intent` is accepted on all eighteen and is never rendered.

**A `chart` takes exactly one of `measure` or `measures`.** `measures` (2 to 4
keys) draws a multi-series chart and forbids `series`. `cross_filter: true`
restricts the chart to `bar` or `hbar` and forbids both `series` and `measures`.
`viewer` (any of `sort`, `limit`) adds live controls and is refused alongside
`measures` or `series`.

**A `filter` takes at most one of `multi` and `range`**, never both.

**A `custom` tile needs at least one of `html` (up to 100,000 characters) or `js`
(up to 200,000 characters).** Its `reads` array names 1 to 8 datasets, and the
runtime hands the tile exactly those. The published page runs in a sandboxed
opaque origin, so browser storage and cookies are unavailable to it, though
cross-origin `fetch` is not blocked. See
[what a tile cannot do](/reference/runtime-attributes#what-a-tile-cannot-do).

## Honest degradation

The rule these tiles follow is that **a tile that cannot be exact says so, in
place, with the reason.** It never renders a plausible wrong picture, and it never
silently drops the part it could not compute.

| Type | What it does when it cannot be exact |
|---|---|
| `treemap` | The rectangles are laid out against the dataset's own total, never against the sum of the rectangles. If a `limit` truncates the members, or a member cannot be resolved, **the rest of the box stays empty** rather than being renormalized to fill it. It refuses outright on a measure that does not decompose, on a negative value, and when the dataset reports no positive total. |
| `waterfall` | Every step is positioned where the previous one ended, so one missing contribution moves all of them. **The whole chart is withheld** rather than drawn with a step that would read as "no change". It also refuses when the dataset reports no total, and when the contributions do not reconcile with it. |
| `stacked` | A negative segment means a stacked bar's length would stop being the sum of its parts, so **the same exact values are drawn grouped instead**, with a line saying why. A 100 percent stack whose column mixes signs, or whose column totals zero, is withheld: no share of it would be a true proportion. |
| `pie`, `donut` | Refused on a measure whose parts do not compose to its whole, on a negative slice, when the slices add up to more than the dataset's own total, and past five slices (the width of the validated mark palette). When the slices do not account for the whole, that is disclosed rather than hidden. |
| `matrix`, `heatmap` | A subtotal is re-evaluated by the resolver, never summed from the children on screen. A cell the dataset cannot resolve renders as unavailable and is never coloured as though it were a value. |
| `drilldown` | An `Other` residual row is composed by the resolver from the members not shown. Where the measure cannot be recombined across those members, the `Other` row renders as unavailable with the reason, and the members that are shown keep their exact values. |
| `chart`, `table`, `kpi` | A binding the dataset cannot answer under the current filters renders as unavailable with the reason, in place of the figure. |

Every one of those refusals is a runtime behaviour on the published page, under
whatever filters the reader has applied. They are separate from the publish-time
refusals, which stop a wrong dashboard existing at all: see
[Errors](/reference/errors).

## Where a tile truncates

Some tiles cap how much they render even when you set no `limit`. Past the cap
they truncate and disclose it on the tile.

| Type | Default before truncation | Ceiling you can raise it to |
|---|---|---|
| `matrix`, `heatmap` | 200 rows, 100 columns | 1,000 rows via `limit` |
| `scatter` | 500 points | 2,000 via `limit` |
| `treemap` | 24 rectangles | 200 via `limit` |
| `waterfall` | 40 contribution bars | 200 via `limit` |
| `drilldown` | 200 members per level | not raisable, see below |
| `stacked`, `combo` | 60 x-axis positions | 400 via `limit` |
| `pie`, `donut` | 5 slices, and this is a hard refusal rather than a truncation | not raisable |

**`top_n` on a drilldown only ever cuts.** The schema accepts a `top_n` up to
1,000, but the renderer clamps the members it draws to 200 regardless, so a
`top_n` above 200 changes nothing. Use it to show a Top 10 with an `Other`
residual, not to widen a level.

## Check it worked

Publish with `dry_run: true` and read the warnings. Several tiles carry
publish-time checks that fire before the page exists: a funnel stage that no
dimension member matches, a stacked chart over a measure that does not add up, a
series dimension whose cardinality is past the palette. Fixing those at publish is
cheaper than discovering the tile withheld itself in front of a reader.
