Skip to content

Tables and Text

Tables present values directly in rows and columns, making lookup, exact reading, and dense comparison possible; this family includes plain text tables, colored tables, and spark tables. They are most useful when the reader needs exact numbers, many values at once, or a structured reference view rather than a strongly shaped visual pattern.

This page will also cover other data-powered text-like outputs that are not really Vega-Lite charts at all, such as KPI blocks, large single-value callouts, and future narrative or AI-generated summary text. In other words, this family is not just about tables as rows and columns; it is about text-oriented outputs that are driven by data and are often used when exact reading, summarization, or direct communication matters more than visual encoding.

A chart's control surface is the full set of authored properties available on a single chart. In Dataface, that surface is primarily top-level chart fields plus a typed style object.

This page is intentionally family-oriented rather than exhaustive. For the implementation-backed source of truth, including table, KPI, spark, and spark_bar property coverage, see the YAML Schema Reference.


Table Charts

Use type: table when exact values, scanning, and dense comparison matter more than mark-based trend reading.

Minimum Required for a Table

Dataface field Maps to renderer behavior Allowed values Notes
query table data rows Query name or query reference Supplies the dataset.
type: table table SVG renderer Literal table Selects the table renderer.

Table-Specific Style

Table-specific style fields go directly under style: (e.g. style.row_numbers.visible, style.columns). Chart-level style: is typed as TableChartStylePatch — its fields sit at the root of the chart's style: block. Using style.table.* nesting raises a validation error (extra inputs are not permitted).

Dataface field Maps to renderer behavior Allowed values Notes
style.columns per-column display config Mapping of column name → config object Lets you choose columns explicitly and configure labels, formatting, width, alignment, header links, and inline sparks. Use column_name: {} for a bare column with defaults.
style.column_defaults table-wide column defaults TableColumnDefaultsConfig object Sets label, width, align, format, background, and font for all columns; per-column entries override field-by-field.
style.header_overflow header overflow behavior clip, truncate, wrap-two, or wrap Controls how long table headers clip, truncate with ellipsis, or wrap.
style.background chart SVG background wrapper Color value Applies a chart-level background fill behind the rendered table SVG.
style.column_layout.width_similarity_threshold column cluster equalization threshold Float 0.01.0 (default 0.8) Auto-width columns whose min/max ratio ≥ this value are snapped to a shared width before budget allocation. 0.8 = within ~20% get equalized; 1.0 = disabled (pure proportional); 0.0 = all auto-columns equal.
style.symbol_mode currency-prefix / magnitude-suffix placement on numeric columns anchors (theme default) or all anchors shows the full formatted value only on the first data row and on summary/total rows, stripping the prefix and suffix from plain middle rows — the anchor rows carry the unit so the reader doesn't need it repeated on every line. all shows the full formatted value (prefix + number + suffix) on every row.

To disable column equalization for a chart that needs strict proportional sizing — for example, a revenue waterfall where the column widths carry meaning — set the threshold to 1.0:

style:
  column_layout:
    width_similarity_threshold: 1.0  # disable equalization; use strict proportional widths

Every built-in theme defaults symbol_mode to anchors — a currency or percent symbol only at the top and bottom of a numeric column. To show the symbol on every row instead, set symbol_mode: all:

style:
  symbol_mode: all  # "$1,234" on every row instead of just the first data row and the total row

Row Presentation (style.row)

The style.row block controls body-row defaults and per-role overrides for summary and total rows. The singular row name avoids confusion with the face-level rows: layout key.

Dataface field Maps to renderer behavior Allowed values Notes
style.row.role column id for per-row role Column name (string) Per-row value: value, summary, or total.
style.row.height body row height (px) Number Body row height.
style.row.rule.width row separator width (px) Number Row separator width.
style.row.rule.color row separator color Color value Sets the row separator color; overrides the theme default.
style.row.roles.summary.font.weight summary row font weight "400", "500", "600", "700" Summary-row font weight.
style.row.roles.summary.background summary row fill Color value Fill behind summary rows.
style.row.roles.total.font.weight total row font weight "400", "500", "600", "700" Total-row font weight.
style.row.roles.total.background total row fill Color value Fill behind total rows.
style:
  row:
    role: kind              # column whose per-row value is the role
    height: 15
    rule:
      width: 2
      color: "#D32F2F"
    roles:
      summary:
        font:
          weight: "500"
      total:
        font:
          weight: "700"
        background: "#F5F5F5"

Row Numbers (style.row_numbers)

The style.row_numbers block injects a synthetic leading column that numbers data rows 1, 2, 3, ... — the same presentation as Excel, Google Sheets, and Looker's show_row_numbers. The column is transparent to style.columns (authors don't list it), to conditional_formatting rules keyed by column name (no rules target it), and to the data pipeline (it is a chart-layer concern, not a query column).

Dataface field Maps to renderer behavior Allowed values Notes
style.row_numbers.visible toggle on/off true or false Default false — off unless set.
style.row_numbers.header column header text String Default "#".
style.row_numbers.align cell text alignment left or right Default right, matching numeric convention.
style:
  row_numbers:
    visible: true   # minimum v1 opt-in
    header: "#"     # defaults; include to override
    align: right

Pagination behavior: numbering is continuous across pages. Page 2 of a 100-per-page table starts at row 101; it never resets to 1. The column width sizes against the total row count (not the per-page count), so page 1 and page 5 of a 200-row table have the same row-number column width.

Summary / total rows: the row-number cell is blank on rows tagged as summary or total (via style.row.role). The sequence counts data rows only.

Table Pagination

Tables support client-side row pagination via style.pagination. This controls how many rows are visible per page — it is a presentation concern, distinct from query-level limit which controls how many rows are fetched.

Dataface field Maps to renderer behavior Allowed values Notes
style.pagination enables row paging Object Use the object form shown below.
style.pagination.enabled toggle pagination on/off true or false Defaults to true when pagination is present.
style.pagination.page_rows rows per page Positive integer Optional; when omitted the renderer uses its default.

Use the full object form:

style:
  pagination:
    enabled: true
    page_rows: 25

Design note: style.pagination is purely presentational. Use query-level limit when the intent is to fetch fewer rows. The Looker migration exporter maps limit_displayed_rows / num_rows to style.pagination.page_rows, preserving the distinction between data truncation and UI paging.

Conditional Formatting (conditional_formatting)

Tables (and other chart types) support cell-level conditional styling through the chart-level conditional_formatting: block — keyed by query column name, with a when: list evaluated top-to-bottom like spreadsheet rules. This is the canonical mechanism for changing a cell's background, font.color, or font.weight based on its value. There is no separate cell_style field on style.columns[]; cell-level decisions live here.

Predicate Meaning
gte: <number> value is greater than or equal to
gt: <number> value is strictly greater than
lte: <number> value is less than or equal to
lt: <number> value is strictly less than
eq: <value> value equals (string or number)
default: true catch-all; place last

Each when entry can set background (color), font.color (color), and font.weight ("400""700"). Rules are evaluated per-row, per-column; the first matching predicate wins.

charts:
  cf_revenue_table:
    type: table
    query: product_category_revenue
    conditional_formatting:
      revenue:
        when:
          - gte: 50000
            background: "#dcfce7"
            font:
              color: "#166534"
              weight: "bold"
          - gte: 30000
            background: "#e0f2fe"
          - default: true
            background: "#fef3c7"
      category:
        when:
          - eq: Electronics
            background: "#ede9fe"
          - eq: Accessories
            background: "#cffafe"
          - default: true
            background: "#f4f4f5"

Why chart-level, not column-level: rules are keyed by column name inside the conditional_formatting block, which keeps style.columns[] focused on layout (label, format, width, align, link, spark) and conditional decoration discoverable in one place. Authors who think "I want red below zero on the revenue column" find one block instead of digging into per-column blocks.

For value-driven gradients (continuous color across a numeric range), see the scale: config — separate from when: rules. Both compose under conditional_formatting.

Table Column Config

style.column_defaults sets shared defaults applied to every column in style.columns. Per-column entries override field-by-field:

style:
  column_defaults:
    label: " "
    width: 36
    align: center
  columns:
    c1: {}
    c2: {}
    c3:
      background: "#fee2e2"  # overrides background; label/width/align come from defaults

When all columns share the same presentation (labels, width, alignment), you only write the defaults once and use empty config objects for columns that only inherit defaults.

Each style.columns.<column_name> entry can set:

  • column
  • label
  • format
  • width — hard pin to an exact pixel value or percentage (e.g. 200 or "20%"). Cannot be combined with max_width:.
  • max_width — cap on auto-sized text columns (see below). Cannot be combined with width:.
  • align
  • header_link
  • link — cell-level hyperlink; supports a static URL, a column ID (uses per-row value), or a template with {{ column_id }} placeholders
  • spark
  • background
  • font

style.column_defaults supports label, width, align, format, background, and font. Data-dependent fields (link, header_link, spark, scale, glyph) are not available as defaults.

Auto-sizing: compact vs text columns

The table auto-sizer classifies each column as compact or text based on its measured content demand:

  • Compact columns (demand ≤ 220px, or spark columns) are pinned to their measured demand. Short enums, numbers, dates, and short strings are compact by default.
  • Text columns (demand > 220px) compete proportionally for the remaining budget after compact columns are pinned.

This means a freeform notes or description column no longer squashes every compact column down to unreadably narrow widths. The compact columns keep their natural size; the text column gets whatever is left.

When compact columns' total demand exceeds the available width the table accepts overflow (horizontal scroll) rather than squishing — clipping is honest, mid-word wrapping is not.

max_width: — capping a text column

Use max_width: on a text column to prevent it from growing beyond a ceiling even when there is spare budget:

style:
  columns:
    csm_name: {}
    account: {}
    arr:
      format: "$,.0f"
    next_steps:
      max_width: 400   # cap the freeform text column; compact columns absorb the remainder

max_width: accepts an integer (pixels) or a CSS-style percentage string ("30%"). It is mutually exclusive with width: — setting both raises a validation error at compile time.

When a text column is capped below its natural budget share, the leftover budget is redistributed to the compact columns proportionally, so the table always fills its tile.

Inline spark configs support small in-cell visual encodings: line, area, bar (single horizontal bar, absolute magnitude), bar-normalize (single horizontal bar scaled to a ceiling, with background track), and columns (multi-value vertical bars).

Date and Datetime Formatting

Date and datetime values from the warehouse (DATE, TIMESTAMP, TIMESTAMPTZ columns) are formatted at render time using the theme's date_short format alias — no SQL-side strftime is required. The default date_short value is "%-d %b %Y", which renders 2024-05-19 as 19 May 2024.

To override the format for a specific column, set format: on that column entry using a strftime-style spec beginning with %:

style:
  columns:
    event_date:
      label: "Event Date"
      format: "%B %d, %Y"   # "May 19, 2024"

Assigning a non-strftime format spec (such as a d3 numeric format like ",.0f") to a date column raises an error at render time — use a %-prefixed strftime spec or omit format: to use the date_short theme alias.

Date columns are right-aligned and excluded from text-wrap layout automatically. Timezone-aware datetimes are converted to UTC before the date component is extracted, so the displayed date is always consistent regardless of the server's local timezone.


KPI Charts

Use type: kpi when the output is fundamentally one important value rather than a plotted series.

Minimum Required for a KPI

Dataface field Maps to renderer behavior Allowed values Notes
query KPI data row Query name or query reference Supplies the dataset.
type: kpi KPI renderer Literal kpi Selects the KPI renderer.
value KPI value binding Column reference (string column name) Chooses the value to display.

format is especially important for KPIs because it controls how that single value is rendered.


Callout Charts

Use type: callout for a bordered message card inside a dashboard tile. Callouts do not run queries — they are static content with semantic coloring driven by style.tone:.

Runtime chart failures (query errors, data-shape mismatches, render failures) also render as callout cards with explicit tone: negative, using the same renderer and style.charts.callout structure defaults.

Minimum Required for a Callout

Dataface field Maps to renderer behavior Allowed values Notes
type: callout Callout renderer Literal callout Selects the callout renderer.
message Body text String Required. Wraps inside the tile width.
title Heading String Optional heading above message.
style.tone Palette role info, positive, negative, warning Optional. Defaults to info.
charts:
  migration_warning:
    type: callout
    title: Migration warning
    message: >
      Two tiles could not be migrated automatically. Review the source
      dashboard before publishing.
    style:
      tone: warning

rows:
  - migration_warning

Theme defaults live under style.charts.callout (padding, border, title/message typography). Per-chart style.tone: selects which palette role supplies background, border, and text colors (info.*, positive.*, negative.*, or warning.*).


Spark Bar Charts

type: spark_bar is a compact ranked text-plus-bar chart used by inspector-style summaries. For authored dashboards, prefer a table with an inline spark column (spark.type: bar or spark.type: bar-normalize) when you need custom column order, formatting, row styling, or conditional formatting.

When you do use type: spark_bar, the data fields are x for the label column and y for the value column. label: and value: are not accepted on spark_bar charts.

charts:
  owners_ranked:
    type: spark_bar
    query: owner_counts
    x: owner
    y: objects

Spark-Bar Style

Dataface field Maps to renderer behavior Allowed values Notes
style.max_bars row cap Integer Maximum number of visible rows before truncation.
style.spark_bar.label.visible left label visibility true or false Set false to hide labels beside the bars (default: true).
style.spark_bar.count.visible right count visibility true or false Set false to hide right-side numeric counts (default: true).
style.spark_bar.bar.height row/bar height Integer Controls compactness of the display.
style.spark_bar.bar.color bar fill color Color value Spark-bar paint surface.
style.spark_bar.bar.background bar track color Color value Spark-bar background/track paint surface.