demo D06
Loading data after the grid exists in htmx
An empty grid that fills from a fetch, with the loading state between
rows.load(data)
This grid is created empty and then filled from a fetch, showing the loading state in between. It matches how most apps really work, the shell renders first and the rows arrive a moment later, so you can build the grid before the data exists and drop it in when it lands.
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">
<script src="https://cdn.jsdelivr.net/npm/htmx.org@2.0.4/dist/htmx.min.js"></script>
<!-- htmx asks your endpoint for the rows the moment the page loads, and asks
again whenever the reader sorts or filters. The reply is ordinary table
markup, the same rows a server template already knows how to render. -->
<div id="grid" hx-get="/api/circuits" hx-trigger="load, lattice:query-changed"
style="height: 540px"></div>
<script type="module">
import { createGrid, driveServerMode } from 'https://cdn.latticegrid.dev/lattice-grid@1.107.0/modules/htmx.esm.min.js';
const el = document.getElementById('grid');
// The grid mounts empty and shows its empty state until the reply arrives.
const grid = createGrid(el, {
// Each row's data-id arrives as __row, so that is the key here.
rowKey: '__row',
columns: [
{ field: 'circuit', title: 'Circuit', layout: { width: 180 } },
{ 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' } },
],
});
// The reply is read straight into the grid rather than swapped into the page,
// and the sort and filter in force travel with each request.
driveServerMode(grid, el);
</script>
Populating a grid after it mounts
Most integrations construct the grid before the data exists: a dashboard shell renders, an API call goes out, and the rows arrive some milliseconds later. Lattice Grid separates these two moments deliberately. createGrid builds the columns, the header and the empty body immediately, and rows.load(data) fills it whenever the fetch resolves, without a second construction step or a full remount. This is the shape a JavaScript data grid needs for any screen backed by a remote call, a websocket handshake, or a route that streams from a loader before its data dependency settles.
Between construction and the load call, the grid shows a loading state rather than an empty table with no explanation, so the viewer sees a grid that is working rather than one that has failed to render. Once rows.load runs, the body populates in place: scroll position, column widths and any sort or filter already configured on the grid all carry over, because the grid was never torn down to receive its data.
The same call handles a refresh, not only the first load. Calling rows.load again replaces the row set cleanly, which makes it the entry point for both the initial fetch and any subsequent reload triggered by the host application.
How do you show a loading state before a data grid has data?
Construct the grid immediately with createGrid(el, { columns, rows: [] }), so the header and empty body render before the fetch completes. Lattice Grid displays a built-in loading state for the empty body automatically; when the request resolves, call rows.load(data) to fill it, and the same call works again for any later refresh.