Lattice Grid Buy a licence

demo D45

Rules from configuration in htmx

Colouring cells by value, seeded at build time

formatting: { col: [{ when, style }] }

This grid colours cells by their value from rules declared in configuration rather than inline checks scattered through code. It keeps conditional formatting maintainable as thresholds grow, so a dozen colouring rules across several columns live in one readable place.

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="formatting-rules-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="0"><td>DFB-EDI-100000</td><td>Edinburgh</td><td>live</td><td>100</td><td>94.88</td></tr>
    <tr data-id="1"><td>MPL-BIR-100001</td><td>Birmingham</td><td>provisioning</td><td>10000</td><td>4324.6</td></tr>
    <tr data-id="2"><td>DFB-LON-100002</td><td>London</td><td>live</td><td>2000</td><td>1031.02</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';

  // 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('formatting-rules-table'), {
    // Seeded from configuration, keyed by column id. The same list is what
    // grid.formatting.list('charge') returns and what a saved view carries.
    // Order is meaning: the first rule that matches wins, so bands run high
    // to low and the last one needs no lower bound.
    formatting: {
      charge: [
        { id: 'charge-high', when: { op: 'gte', value: 3000 }, style: { background: '#fbeceb', color: '#b03030', fontWeight: '600' } },
        { id: 'charge-mid', when: { op: 'between', value: 1200, value2: 3000 }, style: { background: '#fdf3e0', color: '#9a6400' } },
        { id: 'charge-low', when: { op: 'lt', value: 1200 }, style: { background: '#f1f3f5', color: '#5b6570' } },
      ],
      status: [
        { id: 'status-ceased', when: { op: 'eq', value: 'ceased' }, style: { background: '#f1f3f5', color: '#5b6570' } },
        { id: 'status-provisioning', when: { op: 'eq', value: 'provisioning' }, style: { background: '#e7f0fb', color: '#1a6bc7' } },
        { id: 'status-live', when: { op: 'eq', value: 'live' }, style: { background: '#e8f5ee', color: '#1a7f4b' } },
      ],
    },
    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' } },
    ],
  });
</script>

Colouring cells from declarative rules, not row-by-row logic

Conditional formatting in a JavaScript data grid usually starts as inline checks and grows into a maintenance problem once a dataset has a dozen thresholds across several columns. Lattice Grid takes the rules as configuration instead: the formatting: { col: [{ when, style }] } option accepts an ordered list of predicate and style pairs per column, evaluated against each cell’s value and applied without a render callback per row. A when clause is a plain condition against the cell value or row data; the matching style sets background, text colour, or a class name. This is the shape a developer reaches for when a value needs colouring by range, such as flagging stock below a reorder point, marking overdue dates, or shading a variance column red and green either side of zero, with thresholds known before the grid renders rather than computed live.

Because the rule set is data, not code, it can be built once at build time or generated from a config file and handed to the grid unchanged, keeping the ruleset auditable outside the rendering path. Rules compile into a lookup per column when the grid initialises, so evaluating them during scroll adds a fixed, small cost per visible cell rather than re-parsing conditions on every frame, keeping scroll performance steady on wide, rule-heavy grids.

How do I colour grid cells based on their value?

Use the formatting option and list rules per column as { when, style } pairs: when describes the condition to match against a cell’s value, style sets the background, text colour, or class to apply. Lattice Grid evaluates the rules for each column once at initialisation and applies them per cell during rendering, so thresholds defined ahead of time colour every matching row without per-row callback code.