Lattice Grid Buy a licence

demo D283

Validation declared on the column in React

An invalid edit vetoed with an announced inline error, from rules stated as data

validation: { required, min, max, pattern, oneOf }

This grid states its edit rules as data on the column, required, min, max, a pattern or an allowed list, and vetoes an invalid edit with an announced inline error. It keeps the definition of a good value next to the column, so validation is readable and consistent rather than hand-coded per field.

Building…
Loading a live grid…

This is the React version. The grid mounts through the createLatticeGrid adapter, which takes its configuration as ordinary props and hands back the live grid through a ref. The grid below is the same one every other tab runs.

The configuration

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

<div id="grid"></div>

<script type="module">
  import React from 'https://esm.sh/react@18';
  import { createRoot } from 'https://esm.sh/react-dom@18/client';
  import { createGrid } from 'https://cdn.latticegrid.dev/lattice-grid@1.107.0/lattice-grid.esm.min.js';
  import createLatticeGrid from 'https://cdn.latticegrid.dev/lattice-grid@1.107.0/modules/react.esm.min.js';

  const LatticeGrid = createLatticeGrid({ React, createGrid });

  const columns = [
    { field: 'id', title: 'Order', layout: { width: 120, pin: 'start' } },
    { field: 'reference', title: 'Reference', layout: { width: 130 }, edit: true,
      // A pattern the whole value must match, with its own message.
      validation: {
        required: true,
        pattern: '^(CHG|INC|REQ)-\d{4}$',
        messages: { pattern: 'Use CHG, INC or REQ followed by four digits.', required: 'A reference is required.' },
      } },
    { field: 'team', title: 'Team', filter: { type: 'set' }, edit: true,
      // One of a fixed set, and never blank.
      validation: { required: true, oneOf: ['Core', 'Platform', 'Edge', 'Field'], messages: { oneOf: 'Pick one of the four teams.' } } },
    { field: 'circuits', title: 'Circuits', type: 'number', layout: { width: 110 }, edit: true,
      // A whole number in range: min and max carry the bounds.
      validation: { required: true, min: 1, max: 40, messages: { min: 'At least one circuit.', max: 'Forty circuits at most.' } } },
    { field: 'budget', title: 'Budget', type: 'number', layout: { width: 140 },
      format: { style: 'currency', currency: 'GBP' }, total: 'sum', edit: true,
      // A cross-field rule: the budget is read against the circuits on the
      // same row, so the ceiling moves with the record.
      validation: {
        min: 0,
        messages: { min: 'A budget cannot be negative.' },
        crossField: (value, row) => {
          const circuits = Number((row.data ?? row).circuits ?? 0);
          return Number(value) <= circuits * 5000 ? true : 'At ' + circuits + ' circuits the cap is ' + (circuits * 5000);
        },
      } },
  ];

  const rows = [/* work orders: id, reference, team, circuits, budget */];

  function App() {
    return (
      <LatticeGrid rowKey="id" selection="multiple" edit columns={columns} rows={rows} style={{ height: '520px' }} />
    );
  }

  createRoot(document.getElementById('grid')).render(<App />);
</script>

Validation stated as data, enforced before the value lands

A grid that lets people edit needs to say what a good value looks like. Lattice Grid takes those rules as data on the column: validation accepts required, min and max, minLength and maxLength, a pattern, a oneOf list, and a crossField predicate for a rule that reads the rest of the row. Each rule is checked against a new value before it is written. A failing value is vetoed, so the cell keeps its old value and nothing half-valid ever lands, and the cell is marked with the grid’s own invalid state, an error that is announced to a screen reader rather than shown only as a red border. Correct the value and the mark clears.

Declaring the rules rather than writing them as a function keeps the constraints in one readable place, checkable outside the render path, and lets a rule carry its own message so a person sees “Use CHG, INC or REQ followed by four digits” instead of a generic refusal. Only a person’s edit is gated: a value written by your own code or arriving from a live feed is treated as the authority and lands untouched, so validation guards the keyboard without fighting your data flow.

How do I stop a grid accepting an invalid edit?

Declare the rules on the column under validation: required for a value that may not be blank, min and max for a number or date range, pattern for a shape the whole value must match, oneOf for a fixed set, and crossField for a rule that compares against other fields on the same row. A failing edit is vetoed before it is written, the cell is marked with an announced inline error, and a corrected value clears the mark. Give a rule its own message through messages so the reason is specific rather than generic.