demo D140
Host menu items and rail actions
Adding your own items to the grid menus from the application
menu extension
The configuration
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@toclocoinc/lattice-grid@1.13.0/lattice-grid.min.css">
<script src="https://cdn.jsdelivr.net/npm/@toclocoinc/lattice-grid@1.13.0/lattice-grid.min.js"></script>
<div id="grid" style="height: 540px"></div>
<script>
const grid = LatticeGrid.createGrid(document.getElementById('grid'), {
rowKey: 'id',
selection: 'multiple',
toolPanel: {
side: 'left',
panels: ['columns', 'filters', 'quick'],
exportName: 'lattice-host-actions',
// A string names a built-in; an object is the host's own, placed exactly
// where it sits so it can go between built-ins rather than only after them.
actions: [
'undo', 'redo', 'restore', 'maximise',
{
name: 'failing-only',
title: 'Filter to the failing services',
icon: 'filter',
run: ({ grid }) => {
grid.filters.set({ col: 'state', op: 'eq', value: 'failing' });
},
},
{
name: 'clear-filters',
title: 'Clear every filter',
icon: 'restore',
run: ({ grid }) => grid.filters.clear(),
},
{
// Reads the selection rather than a cell. Nothing selected is a
// no-op rather than a sort of everything.
name: 'sort-by-cost',
title: 'Sort by monthly cost, largest first',
icon: 'sort-desc',
run: ({ grid }) => grid.sort.set([{ col: 'monthlyCost', dir: 'desc' }]),
},
'-', 'export',
],
},
// defaults arrives already built, so the host can prepend, append, reorder
// or drop. Kept whole here and extended, keeping Copy and the rest.
contextMenu: (params, defaults) => [
{
name: `Pin ${String(params.data?.service ?? 'this service')} to the top`,
icon: 'pin',
action: () => params.grid.sort.set([{ col: 'service', dir: 'asc' }]),
},
{
name: 'Filter to this owner',
icon: 'filter',
// Disabled rather than hidden so the menu does not change height
// between cells, which is what makes a context menu hard to aim at.
disabled: params.colId !== 'owner',
action: () => params.grid.filters.set({ col: 'owner', op: 'eq', value: params.value }),
},
{ separator: true },
...defaults,
],
columns: [
{ field: 'service', title: 'Service', layout: { pin: 'start', width: 160 } },
{ field: 'owner', title: 'Owner', filter: { type: 'set' } },
{ field: 'state', title: 'State', filter: { type: 'set' },
cell: { decoration: 'dot', variant: { map: { healthy: 'success', degraded: 'warning', failing: 'danger', unknown: 'neutral' } } } },
{ field: 'openIncidents', title: 'Incidents', type: 'number', total: 'sum' },
{ field: 'monthlyCost', title: 'Monthly cost', type: 'number',
format: { style: 'currency', currency: 'USD' }, total: 'sum' },
],
rows, // service records
});
</script>
Adding application items to the grid’s own menus
The header context menu, the cell context menu and the action rail all ship with a fixed set of built-in operations, but a host application usually has domain actions of its own: flag a row, open a record in another view, copy a value out in a different format. Menu extension puts those actions inside the grid’s existing menus rather than building a parallel one. It is the point most teams reach for once a JavaScript data grid is wired into a real application and the default sort, pin and hide items stop covering what a user needs to do from a row or a cell.
The menu extension option accepts a list of entries per menu, each with a label, a handler and an optional predicate that decides whether the item appears for the row, column or cell it was invoked against, so an action can be scoped to a single column type or hidden for read-only records. Entries render in the same list as the built-in items, sharing icon alignment and keyboard navigation rather than a bolted-on section. Because the predicate runs against the specific target of the invocation, filtering a hundred custom actions down to the two relevant ones costs a single function call per menu open, not a scan of the row or column set.
How do I add a custom action to a data grid’s context menu?
Register it through the menu extension option, supplying a label, a click handler and the menu it should appear in (header, cell or action rail). An optional predicate receives the row, column or cell the menu was opened against and returns whether the item should show, so custom actions can be scoped per column or hidden for particular rows without maintaining a separate menu.