bc-grid
GitHub

Validation

View source

Per-column sync or async validate runs before each commit. Rejected commits keep the editor open, surface the error in a popover, and fire a flash on the cell so sighted users know why their input was bounced.

Try it
  • SKU is sync-validated against the pattern SKU-NNN
  • Name is async-validated (typing "duplicate" rejects after a 600ms simulated round trip)
  • Stock must be a non-negative integer; Price must be > 0
Row
SKU
Name
Price
Stock
p-1
SKU-001
Steel beam, 6m
245
12
p-2
SKU-002
Concrete mix, 20kg
14.5
80
p-3
SKU-003
Bolt set, M12
0.95
1200
p-4
SKU-004
Sealant cartridge
8.75
36
p-5
SKU-005
Hinge pack, 50ct
24
4
Known SKUs: SKU-001, SKU-002, SKU-003, SKU-004, SKU-005

Try this

Each column has different validation rules — try to break each one.

  • SKU: type something that's not SKU-NNN and tab out — sync rejection.
  • Name: clear it and tab — required check fails. Type "duplicate" and tab — async rejection after ~600ms.
  • Price: type 0 or a negative number — rejected.
  • Stock: type a decimal — rejected (integers only).

The contract

A column validator returns either { ok: true } or { ok: false, message }. It can be sync, or it can return a Promise. The async signature receives an AbortSignal; if the user types another keystroke before the previous validate resolves, the grid aborts the in-flight check.

Editor states

  • dirty — the input differs from previousValue. Composes with the cell's normal background.
  • pending — async validate is in flight. The editor stays open with a subtle spinner-ish state while the check resolves.
  • error — last validate returned ok: false. The editor stays open, the error message renders in a popover, and the cell flashes once.
  • All three states are surfaced via a single canonical data-bc-grid-edit-state DOM attribute and CSS variables — style them however you want.

Where validation runs

  1. Editor side first.The editor itself rejects shapes it can't commit (non-numeric number, malformed date). The cell stays open.
  2. Column validate next. Sync first, then async. AbortSignal is honoured.
  3. onCellEditCommit last. The fire-and-forget happy path; the result-shaped opt-in lets the commit handler (e.g. server round trip) reject too.