CE01 Simple Prompt Editor

The minimum viable custom editor: open a browser prompt, then commit or cancel

Live Demo

Click a Notes cell, or focus it and press F2 / Space / start typing.

Code
Prompt-based custom editor
 
Description
The contract
  • Set editor: 'custom' on the column. Without it, cellEditCallback never fires.
  • The callback receives a single context object — not positional arguments.
  • You must call exactly one of ctx.commit(value) or ctx.cancel(), otherwise the grid stays in edit state.
Triggers

The grid handles all the standard triggers (F2, Space, Enter, double-click, click depending on editTrigger, printable char in navigate mode). Your callback only needs to render UI.

CE02 Product Search Dialog

Modal lookup with keyboard nav, highlighted matches, and derived sibling columns

Live Demo

The Product cell stores only a productId; SKU / Category / Unit Price / Total all derive their display from the catalog. Edit Product on row 3 (empty) to see the dialog. Type "mon", arrow down, Enter — every dependent cell refreshes in the same tick.

Edit the Product column to open the search dialog.
Code
Product search column + onrowchange
 
Description
Single source of truth

The row stores only productId. SKU, Category, Unit Price and Total all use formatCallback to look up the catalog at render time.

The "stale derived cells" gotcha

By default the grid re-renders only the edited cell. Sibling columns whose formatCallback reads row.productId will show stale values until something else triggers a render. Fix: reassign grid.items = [...rows] in onrowchange.

Alternative — stamp the row

Instead of deriving sibling cells, you could write row.sku, row.category, row.price directly in the dialog before commit. Each column then reads its own field; no full re-render needed.

Keyboard handling

Listen with capture: true and call stopPropagation() on every key the dialog handles. Otherwise the grid's keyboard handler can run on the same event during the focus-return after commit.

CE03 Inline Color Picker Popover

A floating panel anchored to the cell — not every custom editor needs to be a modal

Live Demo

Click a Color cell. Pick a swatch or use the native color input. Click outside or press Esc to cancel.

Code
Popover-style custom editor
 
Description
The editor UI is up to you

A custom editor is just "render whatever you want, then call commit/cancel." Modal dialogs, floating popovers, native pickers, full sidebars — all valid.

Anchoring to the cell

The grid lives in shadow DOM, but cells expose data-row and data-field on each <td>. Query gridElement.shadowRoot (not document) to get the cell and getBoundingClientRect() to position the popover.

Cleanup matters

Always remove the popover element and any global listeners (keydown, mousedown) on commit/cancel — otherwise they leak across edits.

HTML cell content

Use templateCallback when you need raw HTML in the cell — the string it returns is not escaped. formatCallback is for plain text and escapes its return value. Either way, always escape any user input you interpolate.

templateCallback + drafts

templateCallback receives the original row, not the draft. After a custom-editor commits, the new value lives in the draft until you fold it back into items. If you want the cell to reflect the new value immediately, reassign grid.items in onrowchange (same pattern as CE02). formatCallback does not have this quirk — it reads drafts automatically.

CustomEditorContext reference

PropertyTypeDescription
valueunknownThe current cell value.
rowTThe full row object.
rowIndexnumberIndex of the row being edited.
fieldstringThe column field name.
commit(newValue)(value: unknown) => voidSave the new value and exit edit mode.
cancel()() => voidDiscard changes and exit edit mode.

Pre-v1.0.0 betas used a positional callback signature (row, rowIndex, field, cellElement, commit, cancel). That signature no longer fires — always use the single-context form above.