Skip to content

Custom tiles

When the built-in tile types don’t fit the visual you want, Saiku ships custom renderers that go further while staying safe. All of them are declarative — you describe the result with data, not code.

Each renderer appears as its own entry in the + Add tile menu (under “Custom”). Picking one drops a tile already bound to that renderer; you then configure it in the tile’s ⚙ editor exactly like any other tile — choose a cube, build a query, and supply the renderer’s config.

Ranked list tile

The Ranked list renderer draws the “movers” card most ops dashboards want: a numbered run of rows, each a label and a value, with the value coloured by whether it’s up or down.

Bind it to a query returning a label column and a value column, then configure:

FieldMeaning
SubtitleA muted line under the tile title (“Product department · MoM”)
Label columnBlank = inferred (see below)
Value columnBlank = inferred (see below)
Value formatOptional display pattern — $c1$27.4M. Blank keeps the cube’s own formatting
RowsHow many to show (default 6)
OrderKeep the query’s order, highest first, or lowest first
Value colourBy sign (up green / down red) or plain
Show rank numbersThe leading 1, 2, 3…

Left blank, the columns are inferred structurally: the value is the first measure column in the result and the label is what’s left. That holds even when a dimension’s captions look like numbers — a prescriber decile (10.0), a year, a store number — which is exactly where guessing from the text would get it backwards.

Value format takes the same pattern vocabulary as the KPI tile and the ECharts value axis: $cN compact currency, $N plain currency, N% percent, N fractional digits. Worth setting on any currency measure — a top-N card of raw $27,432,535.99 rows is hard to scan.

Sorting happens before the row limit, so “highest first, 3 rows” is genuinely the top three of the whole result rather than the first three re-ordered. Colours and type follow the App theme — no CSS needed.

ECharts option tile

The ECharts option renderer lets you author a chart by writing an ECharts option object directly. It’s the escape hatch for shapes the built-in Chart tile doesn’t expose — custom axis arrangements, rose variants, unusual visual maps, and so on.

Because your option is handed to a live charting library, it is validated against a safe subset before it ever renders. The rules, enforced at every depth of the object:

  • No function values. ECharts calls things like formatter functions with live data and DOM, so any function anywhere in the option is rejected. (Plain JSON can’t express a function; the check guards against a live object sneaking one in.)

  • No remote URLs. Off-origin http(s):, protocol-relative //host, url(...) targets pointing off-origin, and non-image data: URIs are all rejected — they’re exfil / SSRF vectors. What’s left is same-origin and relative references, plus data: images in PNG, JPEG, GIF or WebP only.

    Note SVG is not on that list, even as a data: image. An SVG can carry script, so it’s excluded on purpose — use a raster export if you need an inline icon.

  • Allowlisted keys only. Only curated top-level keys (title, grid, xAxis, yAxis, series, legend, tooltip, color, backgroundColor, visualMap, radar, polar, and a handful more) and a curated set of per-series fields are accepted. Anything outside the allowlist is rejected rather than silently dropped — the validator fails closed.

If your option violates any rule the tile shows a validation error instead of rendering, so you can fix it. The query you bind supplies the data (categories + series) the option draws.

Theme first, option second

Your option is layered over the App’s themed baseline. Anything it states wins; anything it leaves unsaid — title colour, axis label colour, gridlines, the series palette — is inherited from the theme.

Write only the parts that are genuinely bespoke. An option full of hard-coded hex values looks identical on day one and stops matching the App the first time somebody changes preset.

Formatting the value axis

Because functions are rejected, you can’t format an axis the usual ECharts way — axisLabel.formatter would have to be a function. Instead the editor has a Value axis format field taking the same pattern the KPI tile uses:

PatternRenders
$c0$149K — compact currency
$c1$48.2K
$2$99.50
1%15.6%
01,234

It’s applied to every type: "value" axis and compiled at render time, so you never supply code and the no-functions rule stays absolute. Category axes are left alone — a string template like "W{value}" in your option still works there, since that’s declarative.

Graph tile

The Graph renderer turns a query’s records into a node-and-edge graph — an ownership tree, a relationship map, a flow between entities. Instead of an option object, you give it a column mapping: which columns in your result are the endpoints, ids, labels, and weights.

FieldRequiredMeaning
sourceColyesColumn holding each row’s link source endpoint
targetColyesColumn holding each row’s link target endpoint
idColyesColumn holding a node’s canonical id (so a label can attach to the right node). For a plain edge list, set it equal to sourceCol
labelColnoColumn holding a friendly display name for the idCol node
valueColnoNumeric column carried onto each link and summed into node weight
layoutnoforce (default) or circular

Each row becomes one directed link source → target; nodes are collected from every endpoint and de-duplicated by id. Rows missing an endpoint are skipped. When you set valueCol, its value weights both the link and its endpoint nodes — node size is scaled relative to the weights in that graph, so the heaviest node always reaches the top of the size band whatever the measure’s units are. A zero or negative weight is the lightest node, not an unweighted one.

Configuring a custom tile

The flow is the same for all of them:

  1. + Add tile → Ranked list (or ECharts option, or Graph).
  2. Open the tile’s ⚙ editor.
  3. Bind a query — pick the cube and build the query whose result feeds the tile.
  4. Supply the config — the ranked-list fields, the ECharts option object, or the graph column mapping.
  5. Save. Invalid config surfaces as an inline error rather than a broken render.
  • Building pages & tiles — the built-in tile types and how binding works.
  • The Chart tile — check here before writing an ECharts option by hand.
  • Plugins — the advanced, admin-installed sandboxed-JS tile for fully custom widgets.