bo-grid v3.1.0

Editing & selection

.md

Inline editing

Edit cells in place with an editor matched to the column type, validate the value, and write it back to your rows.

Mark a column editable: true and its cells can be edited in place. The grid is controlled: it never writes to your data itself, but reports each change through onCellEdit, where you update the row (or send the change to a server first).

Double-click a cell, press Enter on it, or select it and start typing. Status opens a dropdown, and Qty refuses a negative number.

editing.svelte GitHub ↗

Making a column editable

<script lang="ts">
  import { Grid, type ColumnDef } from 'bo-grid';

  const columns: ColumnDef[] = [
    { type: 'text', key: 'symbol', header: 'Symbol' },
    { type: 'number', key: 'qty', header: 'Qty', editable: true },
    { type: 'text', key: 'note', header: 'Note', editable: true },
  ];
  let rows = $state(initialRows);
</script>

<Grid {rows} {columns} height={480} onCellEdit={(e) => (e.row[e.column.key] = e.value)} />

Keep the rows in $state so the cell shows the new value once you write it. The event carries the row, the column and the new value.

Opening and closing the editor

  • Double-click a cell, or press Enter or F2 on the focused cell.
  • Start typing on a focused cell: the editor opens with that character, as in a spreadsheet. (Date and dropdown editors open with Enter or a double-click.)
  • Enter or leaving the cell saves; Tab saves and moves to the next cell (on to the next row at the end of one); Escape cancels. The grid keeps the keyboard afterwards.
  • Picking an option in a dropdown with the pointer saves at once; with the arrow keys, Enter saves.
  • What you type is yours until you save: a live update to the cell does not overwrite it.

The editor for each type

The editor matches the column:

ColumnEditore.value
Number types (number, price, percent, volume, currency, heatmap)a text input with a numeric keypad, so - and . type as expecteda number; a blank, or text that is not a number, is refused
datethe browser’s date pickerepoch milliseconds
Any column with optionsa dropdownthe chosen string
Everything elsetext inputthe typed string

Display widgets (badge, tags, rating, progress and others) and computed columns (value) are not editable by themselves; give a display column an editor to edit it. See Custom editors.

Give an editable column options to pick from a list instead of typing:

{ type: 'text', key: 'status', header: 'Status', editable: true, options: ['New', 'Active', 'Closed'] }

Validation

validate(value, row) runs before a value is saved; return false to refuse it and keep the old value. It sees the parsed value (a number for a number column), and it applies to paste and the fill handle too:

{ type: 'number', key: 'qty', header: 'Qty', editable: true, validate: (v) => Number(v) >= 0 }

To turn typed text into a value yourself (strip a currency sign, read “1.5k”), use parse; see Custom editors.

Undo, paste and fill

Edits, pastes and fills undo with Ctrl/⌘+Z and redo with Ctrl/⌘+Y (or Ctrl/⌘+Shift+Z); a paste or a fill is one step. Paste and the fill handle write through the same validation and call onCellEdit for every cell they change. See Cell selection & clipboard.

A full spreadsheet

Dropdowns, parsed salaries, a date editor, the fill handle and saved layouts together:

Sheet.svelte Open GitHub ↗

Reference

Grid props from the types
onCellEdit (e: CellEditEvent) => void

Called when an editable cell is committed. Update your row data in here.

Example
<Grid {rows} {columns} height={480} onCellEdit={({ row, column, value }) => (row[column.key] = value)} />
fillHandle boolean Default false

Show an Excel-style fill handle at the selection's bottom-right corner; drag it to copy the selected value(s) across the extended range (editable columns only). In-memory mode only.

Column options from the types
editable boolean Default false

Allow inline editing (double-click, Enter or F2 on the focused cell, or type to replace). Number types edit as numbers, date as a date. Display types (badge, boolean, rating, progress, tags, link, avatar, relative, sparkline, custom) edit only with an editor; a computed (value) column never does.

options string[] Default undefined

Editable choices: when set, editing renders a <select> of these options instead of a text input (enum/status columns).

Example
{ type: 'text', key: 'side', header: 'Side', editable: true, options: ['Buy', 'Sell'] }
validate (value: unknown, row: GridRow) => boolean

Validate an edited value before it commits (inline edit, custom editor, paste, fill). Return false to reject and keep the old value. Receives the parsed value.

Example
{ type: 'number', key: 'qty', header: 'Qty', editable: true, decimals: 0, validate: (v) => Number(v) > 0 && Number(v) % 100 === 0 }
parse (raw: string, row: GridRow) => unknown

Turn typed or pasted text into the stored value (runs before the built-in number/date coercion, which it replaces). Return undefined or a non-finite number to reject the input.

Example
{ type: 'number', key: 'qty', header: 'Qty', editable: true, parse: (raw) => Number(raw.replace(/[,\s]/g, '')) }
editor Component<CellEditorProps>

Svelte component that edits this cell in place of the built-in input. Makes any column type editable (with editable: true), including display widgets like rating or tags. It calls commit(value) to save — any value, no parsing — or cancel(); Escape cancels.

Example
{ type: 'rating', key: 'score', header: 'Score', editable: true, editor: StarPicker }