Declarative config keys
Every key accepted by the declarative config passed to build_grid(data, config) or
GridDataEngine.from_config(config) — measures, calculated measures, formatting, filtering,
conditional formatting, tree transforms, pivot knobs, and more. The same config drives the Dash
component and (as options) the framework adapters.
| Name | Type | Default | Description |
|---|---|---|---|
grand_totalAggregation | bool | non-pivot: false; pivot: true | DUAL MEANING by flow. Non-pivot (grid): prepend a synthetic 'Total' grand-total ROW at the top of the tree (default OFF). Pivot: toggle the grand-total COLUMN group across all columns (default ON). Same key, opposite defaults by flow. |
binsBinning | dict[str, {edges, labels?, as?}] | None (no binning) | Numeric range binning (opt-in): derive a labeled string dimension per numeric column via Polars `cut` (applied BEFORE rows/columns/hierarchies). Buckets are right-closed: <= e0, e0 - e1, ..., > e[-1]. Kept as a Polars Enum so buckets sort by range not lexically. Must be a mapping else ConfigError; polars required. Example: bins: {revenue: {edges: [100, 500, 1000]}}. |
bins.<col>.asBinning | str | <col>_bin | Name of the derived bin dimension column (usable in rows/columns like any dimension). |
bins.<col>.edges *Binning | list of break points (non-empty) | — (required) | The N break points -> N+1 buckets. Non-empty list/tuple else ConfigError. |
bins.<col>.labelsBinning | list[str] (len = len(edges)+1) | auto range labels | Override the auto bucket labels; must supply exactly len(edges)+1 labels (in range order) else ConfigError. Auto labels: '<= e0', 'e0 - e1', ..., '> e[-1]'. |
cell_renderersCell renderers | dict[str, name | {type, params?}] | None | Named cell renderer/widget per column (opt-in, presentation only — value stays raw so sort/filter/aggregate keep working). Keyed by column NAME; value is a renderer name shorthand or {type, params?}. Emitted as `cellRenderer` (+ `cellRendererParams`). Same leaf-matching as conditional_formats. Must be a mapping else ConfigError. Example: progress: {type: progressBar, params: {min: 0, max: 100, showValue: true}}. |
cell_renderers.<col>.paramsCell renderers | dict | None | Optional renderer parameters passed through as `cellRendererParams` (e.g. {min, max, showValue} for progressBar, {href} for link). Must be a mapping if present else ConfigError. |
cell_renderers.<col>.type *Cell renderers | enum: sparkline | bar | badge | chip | progressBar | link | rating | boolean | checkbox | email | url | phone | tags | — (required) | Renderer name. Charts sparkline/bar (value = number[]); scalar widgets badge/chip/progressBar/link/rating/boolean/checkbox/email/url/phone/tags. Any other value raises ConfigError. Shorthand: give the name directly as the value (no params). |
column_optionsColumn options | dict[str, {option: value}] | None | Per-column display/behaviour flags (opt-in). Keyed by column NAME; each value maps friendly options to values, translated to the component's column-def props. Same leaf-matching as conditional_formats. Unknown option or non-numeric width raises ConfigError. Must be a mapping else ConfigError. Example: notes: {wrap_text: true, sortable: false}. |
column_options.<col>.editableColumn options | bool | — (opt-in, off) | Make cells editable -> component prop `editable`. |
column_options.<col>.filterableColumn options | bool | component default ON (pass false to disable) | Toggle column filtering -> component prop `enableFilter`. |
column_options.<col>.groupableColumn options | bool | component default ON (pass false to disable) | Toggle column grouping -> component prop `enableGrouping`. |
column_options.<col>.hideableColumn options | bool | component default ON (pass false to disable) | Toggle whether the column can be hidden -> component prop `enableHiding`. |
column_options.<col>.max_widthColumn options | number (px) | — (opt-in) | Maximum column width in px -> component prop `maxSize`. Numeric required. |
column_options.<col>.min_widthColumn options | number (px) | — (opt-in) | Minimum column width in px -> component prop `minSize`. Numeric required. |
column_options.<col>.resizableColumn options | bool | component default ON (pass false to disable) | Toggle column resizing -> component prop `enableResizing`. |
column_options.<col>.sortableColumn options | bool | component default ON (pass false to disable) | Toggle column sorting -> component prop `enableSorting`. |
column_options.<col>.tooltipColumn options | str | — (opt-in) | Header tooltip text -> component prop `headerTooltip`. (Note: `align` is intentionally NOT exposed — the component never consumes def.align, so it would silently no-op.) |
column_options.<col>.widthColumn options | number (px) | — (opt-in) | Fixed column width in px -> component prop `size`. Must be numeric (bool/non-number raises ConfigError). |
column_options.<col>.wrap_textColumn options | bool | — (opt-in, off) | Wrap long cell text -> component prop `wrapText`. |
optionsComponent / Chrome | dict[str, Any] | {} | Component options passed through verbatim into the returned payload as `options` (spread as TensorGrid(**out['options'])). Not otherwise interpreted by build_payload. |
conditional_formatsConditional-format | dict[str, {type, ...}] | None | Declarative continuous cell viz (opt-in): attach a `conditionalFormat` spec to each matching leaf column def (by column NAME). Grid AND pivot (a pivot measure appears in every <colPath>::<measure> leaf, so one entry heatmaps the whole cross-tab). Whole spec is passed through verbatim; `type` must be colorScale/dataBar/iconSet. Example: revenue: {type: colorScale, colors: ["#f8696b", "#ffeb84", "#63be7b"]}. |
conditional_formats.<col>.type *Conditional-format | enum: colorScale | dataBar | iconSet | — (required) | Which conditional-format renderer: colorScale (cell background), dataBar (in-cell proportional bar), iconSet (leading status icon). Any other value raises ConfigError. Other spec keys (colors / color / negativeColor / set) pass through verbatim to the component. |
style_rulesConditional-format | dict[str, list[{if, style?, className?}]] | None | Declarative discrete value -> style/class formatting (complement of conditional_formats). Keyed by column NAME; each value is a list of rules attached as `styleRules` on the matching leaf def, passed through verbatim. Same leaf-matching as conditional_formats. Must be a mapping of lists else ConfigError. Example: margin: [{if: "margin < 0", style: {color: "#e03131", fontWeight: bold}}]. |
style_rules.<col>[].classNameConditional-format | str | None | CSS class applied when `if` is truthy. A rule needs `style` and/or `className` (at least one) else ConfigError. |
style_rules.<col>[].if *Conditional-format | str (formula-DSL predicate) | — (required) | Per-rule condition: a safe-DSL formula evaluated per row against its measure values; when truthy the component applies the rule's style/className. A non-empty `if` is required else ConfigError. |
style_rules.<col>[].styleConditional-format | dict (camelCase CSS) | None | Inline style object applied when `if` is truthy. A rule needs `style` and/or `className` (at least one) else ConfigError. |
auto_groupData | bool | false | Grid flow only: when true AND `rows` is empty, engine.infer_schema(agg, max_levels) auto-derives the row dimensions (and the aggregations when `measures`/`agg` is empty). |
max_levelsData | int | None | None | Cap on the number of dimension levels auto_group's engine.infer_schema derives. None = engine default (uncapped). |
group_byData / Dimensions | list[str] | — (fallback for rows) | Alias for `rows`; used only when `rows` is absent. `rows = list(cfg.get('rows') or cfg.get('group_by') or [])`. |
rowsData / Dimensions | list[str] | [] (empty) | Row-axis dimension columns to group/roll up on (nested in order). Accepts hierarchy names (expanded to their levels) and derived <col>_bin / <col>_<part> columns. Alias: group_by (rows wins if both present). |
date_partsDate parts | dict[str, list[part]] | None (none) | Date-part dimensions (opt-in): derive groupable <col>_<part> columns from a date/datetime/time column, with chronologically-sortable labels. The column must be a temporal type else ConfigError; value must be a list of parts; polars required. Example: date_parts: {order_date: [year, quarter, month]}. |
date_parts.<col>[] (parts) *Date parts | enum: year | quarter | month | day | weekday | hour | — (required list) | Which calendar parts to derive. year (int), quarter ('Q1'..'Q4'), month/day/hour (zero-padded strftime), weekday (ISO 1=Mon..7=Sun). Unknown part raises ConfigError. |
filtersFiltering | passed through to engine.make_column_defs (grid flow) | None | Filter configuration forwarded to engine.make_column_defs(..., filters=filters) in the grid (non-pivot) flow. Not consulted in the pivot branch. |
havingFiltering | str (formula-DSL predicate) | None | Grid flow only (opt-in): a safe formula-DSL predicate over each node's MEASURES (e.g. "revenue > 1000"); nodes that fail are pruned (ancestor paths kept). Refused on a pivot; in lazy/Mode B prunes the shipped root level. Must be a string else ConfigError. |
formatsFormatting | dict[str, str] | {} | Per-column format strings in the Dash component's format DSL `kind[:arg]` (e.g. `currency:USD`, `percentage:1`, `number:2`), keyed by measure/derived-column name. Merged with Measure.format (explicit top-level wins). Also consulted for window-column default formats keyed by the derived `as` name. |
headersFormatting | dict[str, str] | {} | Per-column header labels keyed by measure/derived-column name; merged with Measure.header (explicit top-level wins). Applied to make_column_defs, js calculated columns, and window columns (keyed by the derived `as`). |
hierarchiesHierarchies | dict[str, list[str]] | {} (none) | Named hierarchies (opt-in): reusable fixed-order dimension groups referenced by name in rows/columns; a matching name expands to its ordered levels, other names pass through. No recursion (levels taken literally); duplicate columns dropped (first wins). Must be a mapping else ConfigError. Example: hierarchies: {geography: [region, country, city]}. |
aggMeasures | dict[str, spec] | — (fallback for measures) | Alias for `measures`; used when `measures` is None (`cfg.get('agg') or {}`). |
calculatedMeasures | dict[str, spec] | {} | Post-aggregation calculated measures keyed by output name (distinct from true aggregations). Value forms: DSL/formula string or {dsl}/{formula} (backend, safe), {sql} rejected (it's an agg), {js} (client-side browser expression — grid flow only, refused on a pivot), {python}/{python_code}/{code} (require allow_code=True). Backend calc measures work in a pivot (per column leaf); js measures only in the grid. |
measuresMeasures | dict[str, spec] | list[Measure] | {} (or `agg` fallback) | Base aggregations keyed by output name. Each value is a built-in agg name, a formula-DSL string, an explicit {dsl}/{sql}/{python}/{python_code}/{name} tag, or a Measure list. A `list[Measure]` normalises to the same measures/calculated/formats/headers maps (explicit top-level maps win). Alias: agg. |
measures = [Measure(...)] (typed list)Measures (spec form) | list[dash_tensor_grid.measures.Measure] | — | Typed alternative to the {name: spec} dict. Each Measure(name, agg, format=None, header=None, calculated=False) normalises into the measures (or calculated) map plus merged formats/headers; explicit top-level maps win. Non-Measure items raise ConfigError. Example: measures: [Measure('revenue', 'sum', format='currency:USD')]. |
measures.<name> = "<agg-name>" (built-ins)Measures (spec form) | str: one of the built-in aggregation names (or p<NN> / quantile:<q>) | — | Bare-string base-measure spec resolved against the live aggregation factory: sum, mean, avg, average, min, max, product, count (non-null count), size / count_rows (group ROW count via pl.len, column-independent), n_unique / nunique / count_distinct / distinct_count, range (max-min), median, std, var, first, last, mode, concat / group_concat, plus parametric quantile:<0..1> and percentile shorthand p<0..100> (e.g. p50/p90/p95). A non-agg string falls back to formula.agg. Example: revenue: sum. |
measures.<name> = {dsl} / {formula}Measures (spec form) | {dsl: str} or {formula: str} | — | Explicit safe formula-DSL tag. As a base measure -> formula.agg (aggregation expression); as a calculated measure -> formula.calc (post-aggregation). Never executes arbitrary code. Example: margin: {dsl: "(rev - cost) / rev"}. |
measures.<name> = {js}Measures (spec form) | {js: str} | — | Client-side JS expression tag, evaluated in the browser -> emitted as a column `formula`. Calculated-measure ONLY (a base agg raises ConfigError — the browser cannot aggregate raw rows). Grid flow only: refused on a pivot (would silently drop otherwise). Example: jsmargin: {js: "(rev - cost) / rev"}. |
measures.<name> = {name} / {agg}Measures (spec form) | {name: str} or {agg: str} | — | Mapping form of a plain named aggregation (equivalent to the bare string form) -> ('agg', str). Used when other spec keys are absent. |
measures.<name> = {python_code} / {code}Measures (spec form) | {python_code: str} (alias {code}) | — | Inline Python expression -> _eval_python in a restricted namespace (pl/math/np + a small safe-builtins set). RUNS code, requires allow_code=True else ConfigError. `code` is an accepted alias key. Example: custom: {python_code: "lambda g: g['x'].sum() / g.height"}. |
measures.<name> = {python}Measures (spec form) | {python: "module:attr"} | — | A callable referenced by import path -> _import_callable. RUNS code, so requires allow_code=True else ConfigError. Works as a base agg or a calculated measure (calc flag). Accepts 'module:attr' or 'module.attr'. Example: var: {python: "mypkg.metrics:portfolio_var"}. |
measures.<name> = {sql}Measures (spec form) | {sql: str} | — | Safe SQL aggregation expression tag -> formula.sql. Defines an AGGREGATION measure only; using it under `calculated` raises ConfigError. Safe (parsed, not executed). Example: rev_pu: {sql: "SUM(revenue) / SUM(units)"}. |
col_subtotalsPivot | bool | true | Pivot only: add a subtotal column at each non-leaf column level. Passed to engine.pivot(col_subtotals=...). |
columnsPivot | list[str] | None (no pivot) | Column-axis (pivot / cross-tab) dimensions. Presence of this key switches build_payload into the pivot flow (engine.pivot). Accepts hierarchy names. Alias: pivot. Refuses top_n / window_columns / having / js calculated measures. Example: columns: [year, quarter]. |
contextPivot | bool | false | Pivot only: inject `_grand` / `_col` / `_row` total dicts into each calculated measure's argument, enabling percent-of-column / -row / -grand-total measures. Those must subscript the context dict, so a context measure must be a {python_code}/{python} callable (allow_code=True) — the safe DSL/SQL/JS forms cannot subscript. Example: pct_col: {python_code: "lambda m: 100 * m['revenue'] / (m['_col']['revenue'] or 1)"}. Passed to engine.pivot(context=...). |
pivotPivot | list[str] | — (fallback for columns) | Alias for `columns`; used when `columns` is absent (`cfg.get('columns') or cfg.get('pivot')`). |
row_grand_totalPivot | bool | false | Pivot only: prepend a 'Total' ROW across all row groups. Passed to engine.pivot(row_grand_total=...). |
auto_escalateServer / Lazy | bool | false | Grid flow only (opt-in): when true, engine.recommend_data_mode picks Mode A (full tree, client-side expand) vs Mode B (lazy/server) per the thresholds; the chosen `data_mode` and a `recommendation` block are added to the payload. Default off = byte-identical output. |
node_count_thresholdServer / Lazy | int | None | None (engine default) | Tunes auto_escalate: node-count above which Mode B (lazy) is recommended. Passed to engine.recommend_data_mode(node_count_threshold=...). None leaves the engine default. |
payload_bytes_thresholdServer / Lazy | int | None | None (engine default) | Tunes auto_escalate: serialized-payload byte size above which Mode B (lazy) is recommended. Passed to engine.recommend_data_mode(payload_bytes_threshold=...). None leaves the engine default. |
top_nTree transforms | dict {by, n, descending?, others?, others_label?} | None | Grid flow only: keep the top-N children per level (by a measure) and optionally roll the rest into an 'Others' node. Refused on a pivot. Backed by engine.top_n_children (returns a new top-level list). Requires `by` and `n`. Example: top_n: {by: revenue, n: 5, others: true}. |
top_n.by *Tree transforms | str (measure name) | — (required) | The measure to rank children by for the top_n roll-up. |
top_n.descendingTree transforms | bool | true | Rank direction for top_n (true = largest first). |
top_n.n *Tree transforms | int | — (required) | How many top children to keep per level; the rest are dropped or rolled into 'Others'. |
top_n.othersTree transforms | bool | false | When true, aggregate the remaining (non-top-N) children into a single 'Others' node instead of dropping them. |
top_n.others_labelTree transforms | str | "Others" | Label for the rolled-up remainder node (accepts camelCase alias othersLabel). |
window_columnsTree transforms | list[dict] (each {kind, by, as?, format?, header?, ...}) | [] (empty) | Grid flow only: derived read-only measure columns computed over the aggregated tree (byte-exact oracle for the TS adapters' windowColumns). Refused on a pivot; in lazy/Mode B only the shipped root level carries them. Each entry appends a column def. Example entry: {kind: running_total, by: revenue, as: cum, format: "currency:USD"}. |
window_columns[].asTree transforms | str | per-kind natural key | Output column key. Defaults: running_total -> <by>_cumulative, rank -> 'rank', pct_of_total -> <by>_pct, pct_of_parent -> <by>_pct_parent, delta -> <by>_delta (or <by>_delta_pct if percent), ma -> <by>_ma<window>. A key already owned by a base/calculated/earlier column is skipped (first wins). |
window_columns[].by *Tree transforms | str (measure name) | — (required) | Base measure the window column is computed from. |
window_columns[].denseTree transforms | bool (rank only) | false | rank kind: dense ranking (no gaps after ties) vs standard. |
window_columns[].descendingTree transforms | bool (rank only) | true | rank kind: rank direction (true = largest = rank 1). |
window_columns[].formatTree transforms | str (Dash format DSL kind[:arg]) | kind-dependent (pct/percent-delta -> 'percentage:1'; running_total/abs-delta -> base measure's format; rank -> none) | Format for the derived column in the component's format DSL (NOT a numeral pattern). Precedence: per-spec `format` > top-level formats[as] > kind default. |
window_columns[].headerTree transforms | str | headers[as] else the `as` key | Header label for the derived window column. |
window_columns[].kind *Tree transforms | enum: running_total | rank | pct_of_total | pct_of_parent | delta | ma | — (required) | Window computation. Matched case- and underscore-insensitively. Recognised: running_total (engine.running_total), rank (rank_children), pct_of_total, pct_of_parent, delta (sibling_delta; alias siblingdelta), ma (moving_average; alias movingaverage). Unknown kind raises ConfigError. |
window_columns[].percentTree transforms | bool (delta only) | false | delta (sibling_delta) kind: emit percent change vs previous sibling (default `as` -> <by>_delta_pct, format percentage:1) instead of absolute delta. |
window_columns[].windowTree transforms | int (ma only) | 3 | ma (moving_average) kind: trailing window size; default `as` becomes <by>_ma<window>. |