Action buttons
Add clickable buttons to a row or a column header — an Edit / Drill / Delete affordance — that report
back to your callback instead of doing anything themselves. In Dash this is a dedicated action
column (and per-header headerActions) whose clicks set the action_triggered prop with the
decoded row and path; in the adapters you build the same with a custom cellRenderers button wired
to your own handler.
This is best seen in a running app; the code is the whole feature:
from dash import Input, Output, callbackfrom dash_tensor_grid import TensorGridfrom dash_tensor_grid.engine import GridDataEngine
engine = GridDataEngine(sales)ROWS = ["region", "country"]
cols = engine.make_column_defs(ROWS, {"revenue": "sum"})cols.append(engine.make_action_column( actions=[ {"id": "edit", "label": "Edit", "icon": "edit"}, # built-in icon name… {"id": "drill", "label": "Drill", "iconSvg": "<svg …>…</svg>"}, # …or raw SVG (set allow_html) ], header="Actions",))
grid = TensorGrid(id="grid", row_data=engine.get_tree_payload(ROWS, {"revenue": "sum"}), column_defs=cols)
@callback(Output("log", "children"), Input("grid", "action_triggered"), prevent_initial_call=True)def on_action(a): # Row action: {row_id, action, n, row, path}; header action: {scope: 'column', column, action, n} if a["action"] == "drill": return engine.drill_through(ROWS, a["path"], limit=3) return f"{a['action']} on {a['row_id']}"import { TensorGrid } from '@tensorgrid/react';
// A custom cell renderer returns any node — build a button wired to your handler.<TensorGrid data={data} rows={['region', 'country']} measures={{ revenue: 'sum' }} cellRenderers={{ revenue: (value, node) => ( <button onClick={() => console.log('drill into', node.id)}>Drill</button> ), }}/>;<script setup lang="ts">import { h } from 'vue';import { TensorGrid } from '@tensorgrid/vue';const renderers = { revenue: (value, node) => h('button', { onClick: () => console.log('drill into', node.id) }, 'Drill'),};</script>
<template> <TensorGrid :data="data" :rows="['region', 'country']" :measures="{ revenue: 'sum' }" :cell-renderers="renderers" /></template>import { mountTensorGrid } from '@tensorgrid/vanilla';import { htmlEscape } from '@tensorgrid/core';
mountTensorGrid(document.getElementById('grid'), { data, rows: ['region', 'country'], measures: { revenue: 'sum' }, // Returned HTML is inserted verbatim (trusted); escape any interpolated data. cellRenderers: { revenue: (value, node) => `<button data-drill="${htmlEscape(node.id)}">Drill</button>`, },});// Delegate clicks on [data-drill] to your handler.- Action items are
{id, label?, icon?, iconSvg?, title?}.iconaccepts a built-in name (edit,delete,view,search,download,info,filter,more,plus,check,refresh,star);iconSvgtakes a raw SVG string. - Header actions.
headerActions: [{id, icon, label, title}]on a column def adds buttons to the header; a click firesaction_triggeredwithscope: 'column'and thecolumnid. allow_html. With the default (safe) setting Dash sanitizesiconSvg(strips scripts / handlers); setallow_html=Trueonly for fully trusted, developer-controlled SVG. In the vanilla adapter acellRenderersreturn is inserted verbatim, so escape interpolated data withhtmlEscape.- The decoded
pathon a row action goes straight intodrill_through; see the full events surface.