Skip to content
LogoLogo

Tables & Feeds

Three islands for rows you read one at a time: a table when exact values matter, a feed for things that happened in order, and a search box to find one row in many. Each is a real island below: bind it to fields in your data and the runtime renders it. See the islands overview for the full registry.

table.grid

What it is. A paginated table of raw rows. When to use it: when the exact numbers matter and a chart would hide them: positions, transactions, line items. It needs only a dataset; with no columns it shows every column in the data.

Positions

TickerSharesValue
VWCE312€38,400
AAPL80€16,120
MSFT45€19,850
NVDA30€33,900
BRK.B22€9,240
{
  "type": "table.grid",
  "title": "Positions",
  "dataset": "positions",
  "columns": [
    { "field": "ticker", "label": "Ticker" },
    { "field": "shares", "label": "Shares", "format": "int" },
    { "field": "value_eur", "label": "Value", "format": "eur" }
  ]
}

Key options.

  • columns: [{ field, label?, format? }]: pick and order the columns and set each column's value format. Omit it to show every column.
  • details: [{ field, label?, format? }]: fields hidden from the row and revealed in a click-to-open dialog, each with its own optional value format. Declaring details makes each row clickable.
  • groupBy: { field, titleField?, subtitleField? }: render rows as collapsible sections by field; the section title and subtitle read from each group's first row.
  • drilldown: { island, match }: embed another island in the row-details dialog, its rows filtered by match (a map of drilldown-dataset columnclicked-row field). One level deep: a drilldown island has no drilldown of its own.
  • expand: false: drop the see-all dialog and render every row inline (default true).

timeline.feed

What it is. A reverse-chronological feed of rows. When to use it: logs, activity streams, a journal, anything that reads as "what happened, newest first." It needs a ts (the timestamp) and a titleField; the runtime sorts so the newest row is on top and renders each timestamp smartly (a date-only value as Jun 11, 2026, a real timestamp as Jun 11, 21:30).

Activity

  • Jun 13, 10:05Deposited €2,000transfer
  • Jun 12, 08:30Rebalanced portfoliorule
  • Jun 11, 16:48Sold 12 AAPLmanual
  • Jun 10, 11:02Dividend receivedVWCE
  • Jun 9, 09:14Bought 30 NVDArebalance
{
  "type": "timeline.feed",
  "title": "Activity",
  "dataset": "activity",
  "ts": "ts",
  "titleField": "action",
  "detail": "actor"
}

Key options.

  • detail: a secondary string shown next to the title. kind: a category string.

  • details / drilldown / expand: exactly as on table.grid (click-to-open dialog, embedded filtered island, render-all toggle).

  • groupBy: { field, titleField?, subtitleField? }: collapsible sections, same shape as on the table.

  • Rich rows. Setting any of highlight, stats, or footer switches a row from a single line to a header/stats/footer layout:

    • highlight: { field, format?, unit? }: an emphasized value pinned to the right of the title.
    • stats: [{ field, label?, format?, unit?, color? }]: labeled inline stats under the title; labels default to a palette, color pins one.
    • footer: [{ field, label?, format?, unit?, pill? }]: a meta line led by the timestamp; pill: true renders the value as a badge.

    Each of these takes an optional value format (format) or free-form unit to style its value.

{
  "type": "timeline.feed",
  "title": "Workouts",
  "dataset": "workouts",
  "ts": "ts",
  "titleField": "name",
  "highlight": { "field": "strain", "format": "int" },
  "stats": [
    { "field": "avg_hr", "label": "HR", "unit": "bpm" },
    { "field": "kcal", "label": "Cal", "unit": "kcal" }
  ],
  "footer": [{ "field": "sport", "pill": true }]
}

What it is. A client-side search input over a dataset. When to use it: the dataset is large enough that you'd rather look a row up than scroll. Typing matches rows case-insensitively across fields; results drop down as an autocomplete showing titleField, and selecting one opens that row's full details.

{
  "type": "search.box",
  "dataset": "ingredients",
  "fields": ["name", "category"],
  "titleField": "name",
  "detail": "category",
  "placeholder": "Search foods…"
}

Key options.

  • fields: [...]: the columns a query matches against (substring, case-insensitive).
  • titleField: what each result row shows; detail: an optional secondary line under it.
  • placeholder?: the input's placeholder text.
  • limit?: the maximum number of visible results (default 10).