Lattice Grid Buy a licence

demo D158

Full-width rows in htmx

A row drawn as one band across every column, for section banners

fullWidth: { when, render }

This grid draws a chosen row as one band across every column instead of splitting it into cells. It gives a place for content that belongs between rows, a section banner or a load-more control, without forcing it into the column layout.

Building…
Loading a live grid…

This is the htmx version. A server-rendered table is upgraded in place, so the page is readable before any script runs and gains the full grid when the module loads, which suits a progressively enhanced app.

The configuration

<link rel="stylesheet" href="https://cdn.latticegrid.dev/lattice-grid@1.107.0/lattice-grid.min.css">

<!-- A real, server-rendered table: readable with JavaScript off. data-field on
     each header names the column that cell becomes, and data-id on each row is
     the key the grid carries it under. -->
<table id="full-width-rows-table" data-lattice-grid>
  <thead>
    <tr>
      <th data-field="circuit">Circuit</th>
      <th data-field="region">Region</th>
      <th data-field="status">Status</th>
      <th data-field="bandwidth">Bandwidth</th>
      <th data-field="charge">Monthly charge</th>
    </tr>
  </thead>
  <tbody>
    <tr data-id="sec-Edinburgh"><td></td><td></td><td></td><td></td><td></td></tr>
    <tr data-id="0"><td>DFB-EDI-100000</td><td>Edinburgh</td><td>live</td><td>100</td><td>94.88</td></tr>
    <tr data-id="22"><td>DFB-EDI-100022</td><td>Edinburgh</td><td>provisioning</td><td>1000</td><td>547.72</td></tr>
    <!-- the rest of the rows, rendered by your server -->
  </tbody>
</table>

<script type="module">
  import { hydrateTable } from 'https://cdn.latticegrid.dev/lattice-grid@1.107.0/modules/htmx.esm.min.js';

  // A section banner is inserted before each region's circuits. Banner rows
  // carry no column data of their own, just a kind and a title.
  const byRegion = new Map();
  for (const circuit of circuits) {  // an array of circuit objects
    const region = circuit.region ?? 'Other';
    if (!byRegion.has(region)) byRegion.set(region, []);
    byRegion.get(region).push(circuit);
  }
  const rows = [];
  for (const [region, items] of byRegion) {
    rows.push({ id: `sec-${region}`, kind: 'section', title: `${region}: ${items.length} circuits` });
    rows.push(...items);
  }

  // The markup carries the rows; a server-rendered table's column types are
  // declared in the config hydrateTable takes. The grid replaces the table
  // where it stood.
  const grid = hydrateTable(document.getElementById('full-width-rows-table'), {
    fullWidth: {
      when: (row) => row?.data?.kind === 'section',
      render: (ctx) => ctx?.data?.title ?? '',
    },
    columns: [
      { field: 'circuit', title: 'Circuit', layout: { width: 200 } },
      { field: 'region', title: 'Region' },
      { field: 'status', title: 'Status', filter: { type: 'set' } },
      { field: 'bandwidth', title: 'Bandwidth', type: 'number', filter: { type: 'number' } },
      { field: 'charge', title: 'Monthly charge', type: 'number',
        format: { style: 'currency', currency: 'GBP' }, filter: { type: 'number' } },
    ],
  });
</script>

Drawing a row as one full-width band

A full-width row spans every column as a single band instead of being divided into cells, giving a place for content that belongs between rows rather than inside the table: a section banner introducing a group of rows, a “load more” control at the foot of a page of results, an inline notice, a divider carrying a heading. A developer reaches for this when the body needs structure the columns cannot express. Lattice Grid controls it with fullWidth: { when, render }, where when decides which rows are drawn full width and render returns the markup for that band, so banners and affordances live in the row stream alongside ordinary data rows. As a JavaScript data grid, full-width rows are virtualised with the rest of the body, so a long list broken up by many section banners renders only the rows and bands currently in view and recycles their elements on scroll. A full-width row is announced according to what it holds, so a “load more” band exposes a real button reachable from the keyboard rather than an unlabelled strip, and a section banner reads as a heading in its place in the row order.

How do I add a full-width banner or “load more” row to a data grid?

Set fullWidth: { when, render }. The when function marks which rows are drawn as a single band across all columns, and render returns that band’s markup, so section banners, notices, and “load more” controls sit inline between ordinary rows. Full-width rows are virtualised alongside the rest of the body and can carry real, keyboard-reachable controls.