Lattice Grid Buy a licence

demo D247

One feed, many views in React

Split a single live feed across two grids and a chart, with a pick in one narrowing another

createDataRouter

This splits a single live feed across two grids and a chart at once, and a pick in one narrows another. It gives a dashboard one source of truth shown in several places that all move together, without fanning the feed out to each view by hand.

Building…
Loading a live grid…

This is the React version. The grid mounts through the createLatticeGrid adapter, which takes its configuration as ordinary props and hands back the live grid through a ref. The grid below is the same one every other tab runs.

The configuration

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@toclocoinc/lattice-grid@1.71.0/lattice-grid.min.css">

<div id="app"></div>

<script type="module">
  import React from 'https://esm.sh/react@18';
  import { createRoot } from 'https://esm.sh/react-dom@18/client';
  import { createGrid } from 'https://cdn.jsdelivr.net/npm/@toclocoinc/lattice-grid@1.71.0/lattice-grid.esm.min.js';
  import { createLatticeReact } from 'https://cdn.jsdelivr.net/npm/@toclocoinc/lattice-grid@1.71.0/modules/react.esm.min.js';
  import { createDataRouter } from 'https://cdn.jsdelivr.net/npm/@toclocoinc/lattice-grid@1.71.0/modules/data-router.esm.min.js';

  const { LatticeGrid, useLatticeRouter, LatticeRouterProvider } = createLatticeReact({ React, createGrid, createDataRouter });

  const MONEY = { style: 'currency', currency: 'USD', decimals: 0 };
  const orderColumns = [
    { field: 'id', title: 'Ref', layout: { width: 110, pin: 'start' } },
    { field: 'region', title: 'Region', filter: { type: 'set' } },
    { field: 'service', title: 'Service', filter: { type: 'set' } },
    { field: 'value', title: 'Value', type: 'number', format: MONEY, total: 'sum' },
  ];
  const returnColumns = orderColumns.map((c) => (c.field === 'value' ? { ...c, title: 'Refund' } : c));

  function App() {
    // Built once, in the effect useLatticeRouter runs, and destroyed with it -
    // rebuilding on every render would drop every attached grid and every row
    // it holds.
    const router = useLatticeRouter({ key: 'type', rowKey: 'id' });

    return (
      <LatticeRouterProvider router={router}>
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '14px' }}>
          <LatticeGrid
            route="order"
            rowKey="id"
            selection="multiple"
            highlightOnChange={{ duration: 500 }}
            columns={orderColumns}
            rows={[]}
            style={{ height: '300px' }}
          />
          <LatticeGrid
            route="return"
            rowKey="id"
            highlightOnChange={{ duration: 500 }}
            columns={returnColumns}
            rows={[]}
            style={{ height: '300px' }}
          />
        </div>
      </LatticeRouterProvider>
    );
  }

  createRoot(document.getElementById('app')).render(<App />);
</script>

Splitting one live feed across several grids and a chart at once

Most dashboards carry a single source of truth that has to appear in several places at once: orders in one table, returns in another, throughput on a chart, all of it moving as the same events arrive. Lattice Grid does this without you fanning the feed out by hand. You hand createDataRouter one key to partition on, attach each grid or chart to the value it cares about, and from then on every event that arrives is delivered only to the views it belongs in, each through that view’s own incremental update path. One order lands in the orders table, one return in the returns table, one reading on the chart, and none of the three knows the others exist. Load an opening snapshot in a single call and it is split across every attached view for you; push a mixed batch of changes and each view takes only its share.

The views stay decoupled but need not stay unaware of one another. Cross-grid selection ties two grids together on a shared field: link the orders grid to the returns grid on region, pick an order, and the returns grid narrows to the same region on its own. A reader drills from one view into a related one with a single click, and the feed keeps arriving underneath the whole time. This is the shape behind an operations wall, a trading book split by desk, or any screen where one stream has to drive many honest, live views side by side.

How do I feed one data stream into multiple grids and a chart?

Create a router with createDataRouter({ key, rowKey }), then call router.attach(grid, value) for each grid or headless-grid-backed chart, naming the partition value it should receive. Load an initial snapshot with router.load(rows) and stream changes with router.apply([{ op: 'upsert', row }]); the router routes each record to the matching views only. Add router.link(source, target, { from, to }) to make a selection in one grid narrow another on a shared field.