demo D156
Aligned grids
A summary band whose columns stay locked to the detail grid
alignedGrids: [grid]
The configuration
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@toclocoinc/lattice-grid@1.27.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.27.0/lattice-grid.esm.min.js';
import createLatticeGrid from 'https://cdn.jsdelivr.net/npm/@toclocoinc/lattice-grid@1.27.0/modules/react.esm.min.js';
const LatticeGrid = createLatticeGrid({ React, createGrid });
const columns = [
{ field: 'service', title: 'Service', layout: { pin: 'start', width: 170 } },
{ field: 'team', title: 'Team', layout: { width: 150 } },
{ field: 'owner', title: 'Owner', layout: { width: 170 } },
{ field: 'region', title: 'Region', layout: { width: 150 } },
{ field: 'tier', title: 'Tier', layout: { width: 120 } },
{ field: 'instances', title: 'Instances', type: 'number', total: 'sum', layout: { width: 130 } },
{ field: 'cpuCores', title: 'vCPU', type: 'number', total: 'sum', layout: { width: 120 } },
{ field: 'memoryGb', title: 'Memory GB', type: 'number', total: 'sum', layout: { width: 150 } },
{ field: 'requests', title: 'Requests', type: 'number', total: 'sum', format: { notation: 'compact' }, layout: { width: 150 } },
{ field: 'errors', title: 'Errors', type: 'number', total: 'sum', layout: { width: 130 } },
{ field: 'p95Ms', title: 'p95 ms', type: 'number', layout: { width: 130 } },
{ field: 'monthlyCost', title: 'Monthly cost', type: 'number', total: 'sum', format: { style: 'currency', currency: 'USD' }, layout: { width: 175 } },
{ field: 'budget', title: 'Budget', type: 'number', total: 'sum', format: { style: 'currency', currency: 'USD' }, layout: { width: 160 } },
{ field: 'headcount', title: 'Headcount', type: 'number', total: 'sum', layout: { width: 150 } },
];
const totals = [/* a single totals row */];
const rows = [/* the service rows */];
function App() {
const summaryRef = React.useRef(null);
const [aligned, setAligned] = React.useState(null);
// The detail grid names the summary in alignedGrids, reached through its
// ref: scroll the detail sideways and the summary band tracks it, column
// for column.
React.useEffect(() => {
const summary = summaryRef.current && summaryRef.current.grid;
if (summary) setAligned([summary]);
}, []);
return (
<>
{/* A one-row summary band over the same columns. */}
<LatticeGrid
ref={summaryRef}
rowKey="id"
columns={columns}
rows={totals}
style={{ height: '82px' }}
/>
{aligned && (
<LatticeGrid
rowKey="id"
columns={columns}
rows={rows}
alignedGrids={aligned}
style={{ height: '396px', marginTop: '8px' }}
/>
)}
</>
);
}
createRoot(document.getElementById('app')).render(<App />);
</script>
Locking two grids to one column layout
Aligned grids are two separate grids whose columns stay locked to each other, so a summary band and a detail grid below it read as one table split into sections. A developer reaches for this when a header of totals or a filter row should sit above a long scrolling body but keep its own behaviour: a summary band that never scrolls out of view, a compact overview above a dense detail table, a totals strip that must stay column-for-column with the rows it summarises. Lattice Grid links them with alignedGrids: [grid], pointing each grid at the other so that resizing, reordering, or hiding a column in one is mirrored in the other and the two never drift out of alignment. As a JavaScript data grid, each grid keeps its own virtualised body, so the summary can hold a handful of rows while the detail grid holds many thousands, and only the detail body pays the cost of scrolling. Column widths propagate as measurements rather than repeated per row, so keeping the two aligned adds no per-row work, and each grid remains an independent table region for assistive technology while sharing one column structure.
How do I keep two data grids aligned to the same columns?
Set alignedGrids: [grid] on each grid, pointing it at the other. Resizing, reordering, or hiding a column in one grid is then mirrored in the other, so a summary band and a detail grid below it stay column-for-column aligned and read as one table. Each grid keeps its own rows and its own virtualised body.