Inline Editing in Apex Grid

The Apex grid supports inline editing in cell or row mode. Editing is opt-in at the grid level and at the column level: only columns marked editable: true participate.

Enabling editing

grid.editing = {
  enabled: true,
  mode: 'cell',                    // 'cell' | 'row'
  trigger: 'doubleClick',          // 'click' | 'doubleClick'
};

Mark editable columns:

{
  key: 'name',
  editable: true,
}

Configuration

type EditingConfiguration = {
  enabled: boolean;
  mode?: 'cell' | 'row';
  trigger?: 'click' | 'doubleClick';
  history?: { enabled: boolean; stackSize?: number };  // undo/redo, see below
};

In cell mode, exactly one cell is in edit at a time. In row mode, all editable cells in the active row enter edit together; commitEdit() flushes all pending values for the row in one event cycle.

Programmatic API

await grid.editCell(rowIndex, columnKey);
await grid.commitEdit();
await grid.cancelEdit();

const cell = grid.editingCell;        // currently-edited cell, if any
const row  = grid.editingRow;         // currently-edited row in row mode

Keyboard editing

Besides the pointer trigger, the active cell's editor opens from the keyboard with Enter or F2 (new in 3.4.0; editing was previously pointer-only). While editing, Enter or Tab commits (Tab commits and moves), and Escape cancels. Clearing a number or currency editor commits null rather than NaN, so an emptied numeric cell reads as empty instead of an invalid number. See Accessibility for the full key map.

Events

  • cellValueChanging: cancellable; fires before a cell's value is committed. Read event.detail.oldValue / event.detail.newValue to validate.
  • cellValueChanged: fires after a successful commit.
  • cellValidationFailed: fires when a column validator rejects an edit. Detail: { key, rowIndex, data, value, errors }.
  • rowEditStarted: row mode only; fires when the active row enters edit.
  • rowEditEnded: row mode only; fires when the active row commits or cancels.
  • historyChanged: fires when the undo/redo stack changes (requires editing.history). Detail: { canUndo, canRedo }.

Built-in editors

Editor templates come from the column type. Built-in editors for string, number, boolean, select, rating, and date types are provided. Custom column types register their own editor templates against the column-type registry.

Validation

Since v3.3, columns take a declarative validators array. Validators run inside the commit path (before the cancellable cellValueChanging gate); a failure keeps the editor open, marks the cell (aria-invalid plus an inline error-message node), and blocks the commit.

import { required, min, max, pattern, custom } from 'apex-grid';

const columns = [
  { key: 'name',  editable: true, validators: [required('Name is required')] },
  { key: 'age',   editable: true, type: 'number', validators: [min(18), max(99)] },
  { key: 'email', editable: true, validators: [pattern(/^[^@\s]+@[^@\s]+$/, 'Invalid email')] },
];

Built-ins are required, min, max, pattern, and custom; any (value, ctx) => string | null function works as a validator (return an error string to reject, null to accept). In row mode all pending cells are validated atomically, so there is no partial write. When a validator rejects, the grid fires a cellValidationFailed event:

grid.addEventListener('cellValidationFailed', (event) => {
  const { key, rowIndex, value, errors } = event.detail;
  console.warn(`${key} @ row ${rowIndex} rejected:`, errors);
});

For a simpler ad-hoc check, you can still listen to cellValueChanging and call event.preventDefault() to reject the new value; the grid keeps the cell in edit and the editor focused so the user can correct the entry.

Undo / redo

Opt in to an edit-history stack with editing.history. Every committed cell edit is recorded (single edits, row-mode commits, and enterprise paste / fill each collapse to one step):

grid.editing = { enabled: true, mode: 'cell', history: { enabled: true } };

grid.undo();          // or Ctrl/Cmd+Z
grid.redo();          // or Ctrl/Cmd+Shift+Z / Ctrl+Y
grid.clearHistory();

grid.canUndo;         // boolean getter
grid.canRedo;         // boolean getter

Keyboard shortcuts fire while the grid body has focus, so an open editor's native text undo is untouched. The stack holds 100 commands by default; raise it with history: { enabled: true, stackSize: 200 }. A historyChanged event ({ canUndo, canRedo }) fires whenever the stack changes, so you can enable / disable your own undo / redo buttons.