Lattice Grid Buy a licence

demo D283

Validation declared on the column

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

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

Building…
Loading a live grid…

The configuration

'declarative-validation': () => ({
  rows: orders(5_000),
  config: {
    rowKey: 'id',
    selection: 'multiple',
    edit: true,
    columns: [
      orderCols.id,
      {
        ...orderCols.reference,
        edit: true,
        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.' },
        },
      },
      {
        ...orderCols.team,
        edit: true,
        validation: { required: true, oneOf: ['Core', 'Platform', 'Edge', 'Field'], messages: { oneOf: 'Pick one of the four teams.' } },
      },
      {
        ...orderCols.circuits,
        edit: true,
        validation: { required: true, min: 1, max: 40, messages: { min: 'At least one circuit.', max: 'Forty circuits at most.' } },
      },
      {
        ...orderCols.budget,
        edit: true,
        validation: {
          min: 0,
          messages: { min: 'A budget cannot be negative.' },
          crossField: (value: unknown, row: unknown) => {
            const rec = (row && ((row as any).data ?? row)) as Record<string, unknown>;
            const circuits = Number(rec?.circuits ?? 0);
            const n = Number(value);
            return n <= circuits * 5_000
              ? true
              : `At ${circuits} circuits the cap is ${(circuits * 5_000).toLocaleString('en-GB')}.`;
          },
        },
      },
    ],
  },
  foot: [
    'rules declared as data on the column: required, pattern, range, one-of, cross-field',
    'try REQ-12 in Reference, or 0 in Circuits: the edit is vetoed with an announced error',
    'a corrected value clears the mark; a value your code writes is never gated',
  ],
}),

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.