Lattice Grid Buy a licence

demo D79

A detail pane beside the list

The detail renders into your own element, one record at a time

detail: { target: '#pane' }

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 style="display: flex; gap: 1rem; align-items: stretch">
  <div id="grid" style="flex: 1 1 24rem; height: 540px"></div>
  <div id="detail" style="flex: 1 1 22rem; min-width: 20rem; height: 540px"></div>
</div>

<script>
  const grid = LatticeGrid.createGrid(document.getElementById('grid'), {
    rowKey: 'id',
    selection: 'single',
    toolPanel: {
      side: 'left',
      panels: ['columns', 'filters', 'views', 'quick'],
      actions: ['undo', 'redo', 'export', 'restore', 'maximise'],
      exportName: 'lattice-demo',
    },
    detail: {
      // With a target, nothing expands: the grid's row count never changes and
      // exactly one master is open at a time, so opening a second closes the
      // first. The detail renders into the pane beside the list.
      target: document.getElementById('detail'),
      rows: (row) => row.data.ports,
      config: {
        rowKey: 'port',
        autoHeight: true,
        columns: [
          { field: 'port', title: 'Port', layout: { width: 140 } },
          { field: 'vlan', title: 'VLAN', type: 'number', layout: { width: 100 } },
          { field: 'speed', title: 'Speed', type: 'number', format: { suffix: ' Gb' }, layout: { width: 110 } },
          {
            field: 'state', title: 'State', layout: { width: 130 },
            cell: { decoration: 'dot', variant: { map: { up: 'success', down: 'danger', 'admin down': 'neutral' } } },
          },
          { field: 'peer', title: 'Peer AS' },
        ],
      },
    },
    columns: [
      { field: 'circuit', title: 'Circuit', layout: { width: 160 } },
      { field: 'customer', title: 'Customer', filter: { type: 'set' } },
      { field: 'portCount', title: 'Ports', type: 'number', layout: { width: 100 } },
      { field: 'charge', title: 'Monthly charge', type: 'number', format: { style: 'currency', currency: 'GBP', decimals: 0 }, layout: { width: 170 } },
    ],
    rows,  // circuits, each carrying its own ports array
  });
</script>

Rendering a detail pane for the selected row

A detail pane shows the full record for whichever row is currently selected, drawn into an element you own rather than into a row that expands inline. A developer reaches for this over an inline detail row when the record has more fields than fit the grid’s columns, when the detail needs its own layout separate from the tabular one, or when the list and the detail are meant to sit side by side. Lattice Grid wires this up with detail: { target: '#pane' }, naming the element the current row’s data should render into; selecting a different row swaps the content of that target without touching the row list, so scroll position and any open branches in the tree stay put. Because this is a JavaScript data grid built around row-level updates rather than full re-renders, moving selection only re-renders the pane, not the grid body. The pane receives the row’s data as a plain object, so what appears inside it, from a field list to a nested form, is up to the markup supplied at the target. Selection moves with the keyboard, and the target element updates in place so assistive technology tracking that region announces the new content rather than losing focus context on every change.

How do I show a detail view for the selected row in a JavaScript data grid?

Set detail: { target: '#pane' } on the grid configuration, pointing at the element the detail should render into. Lattice Grid pushes the selected row’s data into that target whenever selection changes, leaving the markup and layout of the pane entirely up to you rather than constraining it to an inline expanding row.