TotalBase
Widgets

Tables

Table, Detail and Pivot table.

In the admin: a Dashboard › a widget › Edit

Table widgets show the rows themselves: as a grid, as one record's fields, or aggregated into a pivot.

The overdue orders table with priority badges, and billing by customer and month as a pivot table with totals.
The overdue orders table with priority badges, and billing by customer and month as a pivot table with totals.

Table

The rows as they come, in the query's order.

RoleTakesUnset
Columnsthe columns shown, in orderevery column, except those starting with _

Acme's overdue orders, the priority as a colored badge and the order's id kept for a click:

SELECT wo.number, c.name AS customer, s.name AS site,
       wo.priority, wo.due_at,
       CASE wo.priority WHEN 'URGENT' THEN 'red' WHEN 'HIGH' THEN 'orange' END AS _priority_color,
       wo.id AS _id
FROM work_orders wo
JOIN sites s ON s.id = wo.site
JOIN customers c ON c.id = s.customer
WHERE wo.status NOT IN ('COMPLETED', 'CANCELLED')
  AND wo.due_at < now()
ORDER BY wo.due_at
LIMIT 50
  • Titles and formats come from each column's presentation in Database: priority reads Urgent, due_at in the viewer's date format. A computed column is titled by its alias.
  • Types: numbers right-aligned in the viewer's format, booleans centered, dates and times in the viewer's zone, a file as its thumbnail.
  • Sorting: a click on a header sorts the rows already loaded: ascending, descending, back to the query's order.
  • Colors: _color tints a row; _priority_color shows priority as badges. See SQL Conventions.
Setting
Column settingsper column: its title and short title, alignment, format, text when empty, labels for true and false, link, look (bold, italic, monospace, color, background), hidden, and its Total
Color columna column whose palette name tints its row; unset, _color. It's never shown
On clickwhat a click on a row does: Open a record with {{row._id}} opens the order's form

Totals

A column's Total, Sum, Average, Minimum, Maximum or Count, adds a footer row. PostgreSQL computes it over every row the query returns, in the same read-only transaction, not over the rows shown, so it stays right when the result is cut at the row cap. It reads in the column's format.

TABLE

The rows as they come - columns starting with _ never show.

Size: 12 × 5 of the 12-column grid, at least 4 × 3 · Also: events, export

DataCodeTakesRequiredUnset
Columnscolumnscategory, number, time, point, fileyesallThe columns shown, in this order. Defaults to every column (but _ ones).
PropertyCodeSectionValues
Column settingscolumnSettingsformatPer column, by name: {label, shortLabel, displayFormat, emptyText, booleanLabels, linkType, options, align, fontSize, bold, italic, mono, underline, strike, color, background, hidden, total} - over what its presentation says. total: sum, avg, min, max or count - a footer row computed by PostgreSQL over every row the query returns (not only those shown), in the column's format.
Color columncolorColumnappearanceA column whose value - a palette name - tints its row. Unset, a column named _color. __color shows that column as colored badges.
On clickclickeventsWhat a click on a mark does: {action: "FILTER", variable, value} sets a variable of this dashboard; {action: "DATAVIEW", dataview, filter} opens a DataView filtered (the where grammar); {action: "DASHBOARD", dashboard, variables, tab}; {action: "RECORD", dataview, pk}; {action: "URL", url, newTab, inEmbeds}. Values are formulas over (_ columns too) and ; targets by id. hint: the tooltip's last line. On a table, a click on a row.
SELECT * FROM (VALUES (1001, 'Ana', 250.5, 'PAID', 'emerald'), (1002, 'Luis', 99.9, 'PENDING', 'amber'), (1003, 'Marta', 410, 'CANCELLED', 'red')) AS t(order_no, customer, total, status, _status_color)

Detail

One row as label / value pairs, with its image: the query's first row. The drawer says when the query returns more than one.

RoleTakesUnset
Columnsthe fields shown, in orderevery column, except those starting with _
Imagea file column, shown as its image above, or beside with two columnsthe first file column

A vehicle chosen in a Select variable:

SELECT v.plate, v.make, v.model, v.year, v.status, v.odometer_km,
       v.insurance_until, v.inspection_until, v.photo
FROM vehicles v
WHERE v.id = $VAR.vehicle::uuid
Setting
LayoutAutomatic (two columns from 6 grid columns wide, one on a phone), One column, Two columns
Field settingsper field: its title, format, text when empty, look
On clickwhat a click on the card does

DETAIL

One row as label / value pairs, with its image - the query's first row.

Size: 4 × 4 of the 12-column grid, at least 3 × 2 · Also: events, export

DataCodeTakesRequiredUnset
Columnscolumnscategory, number, time, point, fileyesallThe fields shown, in this order. Defaults to every column (but _ ones).
ImageimagefilefirstA file column shown as its image, above (or beside, with layout TWO). Defaults to the first file column.
PropertyCodeSectionValues
LayoutlayoutappearanceAUTO, ONE, TWO; default AUTOAUTO: two columns from 6 wide, one on a phone; ONE; TWO.
Field settingscolumnSettingsformatPer column, by name: {label, displayFormat, emptyText, booleanLabels, linkType, options, hidden...} - over what its presentation says (a total doesn't apply).
On clickclickeventsWhat a click on a mark does: {action: "FILTER", variable, value} sets a variable of this dashboard; {action: "DATAVIEW", dataview, filter} opens a DataView filtered (the where grammar); {action: "DASHBOARD", dashboard, variables, tab}; {action: "RECORD", dataview, pk}; {action: "URL", url, newTab, inEmbeds}. Values are formulas over (_ columns too) and ; targets by id. hint: the tooltip's last line. On a detail, the card.
SELECT 'Ana Pérez' AS name, date '2026-10-01' AS last_visit, 12 AS visits, 'GOLD' AS level

Pivot table

The query returns the detail rows; PostgreSQL aggregates them into rows × columns, with subtotals and totals. Nothing is added up on screen, and an average is the real one, never an average of averages.

RoleTakesUnset
Rowsone or more levels down the side, outermost firstthe first column that isn't a number
Columnsby hand: levels across the top, at most 60 distinct valuesnone
Valueswhat is aggregatedevery number column

Billing by customer, a column per month:

SELECT c.name AS customer,
       to_char(i.issued_on, 'YYYY-MM') AS month,
       ii.quantity * ii.unit_price AS billed
FROM invoices i
JOIN invoice_items ii ON ii.invoice = i.id
JOIN customers c ON c.id = i.customer
WHERE i.status <> 'DRAFT'
  AND i.issued_on >= date_trunc('year', current_date)

Rows takes customer on its own. Set Columns to month, and the aggregate of billed to Sum.

Setting
Aggregatesrequired for each value: Sum, Average, Minimum, Maximum or Count
Subtotalsa subtotal for each level of the rows. On by default
Row totalsa total column at the right. On by default
Column totalsa total row at the bottom. On by default
Sort rows bya value's total, ascending or descending, computed by PostgreSQL before the row cap; unset, by the rows' own values
Value settingsper value or row column: its title, format, text when empty
On clicka click on a detail cell, with its dimensions in {{row.<column>}}. A total isn't clickable

Totals come first in the result, so the row cap never cuts them. More than 60 distinct values across the Columns is refused, with the count: group them in the query.

PIVOT

The query's detail rows aggregated by PostgreSQL into rows × columns, with subtotals and totals - never added up on screen.

Size: 12 × 5 of the 12-column grid, at least 4 × 3 · Also: events, export

DataCodeTakesRequiredUnset
Rowsrowscategory, timeyesfirstOne or more levels down the side, outermost first. Defaults to the first column that isn't a number.
ColumnscolumnsnoneLevels across the top (at most 60 values). Optional.
ValuesvaluesnumberyesallWhat is aggregated - each with its aggregate (aggregates). Defaults to every number column.
PropertyCodeSectionValues
AggregatesaggregatesformatRequired for each value: {"total": "sum", "ticket": "avg"} - sum, avg, min, max or count, computed by PostgreSQL over the detail rows (an average is the real one, never an average of averages).
Subtotalssubtotalsappearancedefault trueA subtotal for each level of the rows.
Row totalsrowTotalsappearancedefault trueA total column at the right.
Column totalscolumnTotalsappearancedefault trueA total row at the bottom.
Sort rows bysortByappearance{value: "total", direction: "DESC"} - rows ordered by a value's total. Unset: by the rows' own values.
Value settingscolumnSettingsformatPer value or row column, by name: {label, displayFormat, emptyText...} - over what its presentation says.
On clickclickeventsWhat a click on a mark does: {action: "FILTER", variable, value} sets a variable of this dashboard; {action: "DATAVIEW", dataview, filter} opens a DataView filtered (the where grammar); {action: "DASHBOARD", dashboard, variables, tab}; {action: "RECORD", dataview, pk}; {action: "URL", url, newTab, inEmbeds}. Values are formulas over (_ columns too) and ; targets by id. hint: the tooltip's last line. On a pivot, a detail cell - its rows' and columns' values; a total isn't clickable.
SELECT * FROM (VALUES ('North', 'Jan', 120.5), ('North', 'Feb', 99), ('South', 'Jan', 80), ('South', 'Feb', 140.25), ('North', 'Jan', 30)) AS t(branch, month, total)

Next steps