Lattice Grid Buy a licence

demo D09

Pinned columns

Left and right pinned regions scrolling independently

layout: { pin: 'start' | 'end' }

Building…
Loading a live grid…

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', 'views', 'quick'],
      actions: ['undo', 'redo', 'export', 'restore', 'maximise'],
      exportName: 'lattice-demo',
    },
    columns: [
      { field: 'account', title: 'Account', filter: { type: 'set' }, layout: { pin: 'start', width: 200 } },
      { field: 'service', title: 'Service', filter: { type: 'set' } },
      { field: 'resource', title: 'Resource', layout: { flex: 1, min: 200, max: 320 } },
      { field: 'region', title: 'Region', filter: { type: 'set' } },
      { field: 'environment', title: 'Env', filter: { type: 'set' },
        cell: { decoration: 'pill', variant: { map: {
          prod: 'danger', 'prod-2': 'danger', 'definitely-prod': 'danger',
          staging: 'warning', untagged: 'warning', test: 'info',
          dev: 'success', 'not-prod': 'neutral',
        } } } },
      { field: 'change', title: 'Change', type: 'number',
        layout: { width: 140, min: 140 }, format: { style: 'percent', decimals: 1 } },
      { field: 'cost', title: 'Monthly cost', type: 'number', total: 'sum',
        layout: { width: 170, pin: 'end' },
        format: { style: 'currency', currency: 'USD', decimals: 2 } },
    ],
    rows,  // 10,000 cloud cost records
  });
</script>

Pinning columns to keep key fields in view while the rest scrolls

Pinned columns, also called frozen columns, hold a chosen set of fields fixed against the left or right edge of a JavaScript data grid while the remaining columns scroll independently underneath them. Reach for this whenever a wide table carries an identifying column, such as a name or an order number, that a reader needs alongside whatever metric they have scrolled across to compare, or whenever row-level actions belong on the right edge regardless of horizontal scroll position. Lattice Grid controls this per column through layout: { pin: 'start' | 'end' }, so a column definition declares its own pinned region rather than the grid applying a single global split; a leading identifier column takes 'start' and a trailing actions column takes 'end', with the unpinned columns forming a centre region that scrolls on its own.

The pinned and centre regions render as separate scrolling containers sharing one header and one set of row boundaries, so vertical scrolling stays in sync across all three without a manual reconciliation step. Horizontal scroll position, sort state and column widths in the pinned regions are unaffected by scrolling the centre region, and keyboard navigation moves across the boundary between regions as a single continuous row rather than treating pinned columns as a separate tab stop sequence. Because only the centre region’s off-screen columns are virtualised out of the DOM, adding pinned columns does not change how many rows the grid can hold before scroll performance degrades.

How do you freeze columns in a JavaScript data grid?

Set layout: { pin: 'start' } on a column definition to fix it to the left edge, or pin: 'end' to fix it to the right edge. Lattice Grid renders pinned columns in their own scrolling region alongside the centre columns, keeping them in view while the rest of the row scrolls horizontally.