EditableGrid

Language:

8 rows, 6 columns — basic example with all cell types. ID column is readonly.

IDNameDepartmentStart DateSalaryActive
EMP-001
Alice Johnson
Engineering
2022-03-15
$95,000
EMP-002
Bob Smith
Design
2021-07-01
$82,000
EMP-003
Carol Williams
Marketing
2023-01-10
$75,000
EMP-004
David Brown
Sales
2020-11-20
$68,000
EMP-005
Eva Martinez
Human Resources
2022-09-05
$72,000
EMP-006
Frank Lee
Finance
2021-04-12
$88,000
EMP-007
Grace Chen
Engineering
2023-06-18
$102,000
EMP-008
Henry Davis
Design
2022-12-01
$79,000

Click any cell to edit. Readonly columns (ID, SKU) cannot be edited. Use Tab to move between cells, Enter to move down, Escape to cancel.

EditableGrid

An Excel-like spreadsheet component for editing structured datasets. Supports typed cells (text, number, date, select, checkbox, textarea), readonly columns for fixed identifiers, keyboard navigation, per-cell validation, and row add/delete.

Usage

import { EditableGrid } from "@/components/ui/editable-grid"
import type { EditableColumnDef } from "@/components/ui/editable-grid"

const columns: EditableColumnDef<Row>[] = [
  { columnId: "id", title: "ID", type: "text", readonly: true },
  { columnId: "name", title: "Name", type: "text", validation: { required: true } },
  { columnId: "department", title: "Dept", type: "select", options: [...] },
  { columnId: "startDate", title: "Start", type: "date" },
  { columnId: "salary", title: "Salary", type: "number", aligned: "right" },
  { columnId: "active", title: "Active", type: "checkbox", aligned: "center" },
]

<EditableGrid<Row>
  columns={columns}
  data={data}
  rowIdKey="id"
  onCellChange={(rowId, columnId, value) => updateData(rowId, columnId, value)}
  onAddRow={() => addEmptyRow()}
  onDeleteRows={(ids) => removeRows(ids)}
  enableAddRow
  enableDeleteRow
  enableRowSelection
  bordered
/>

EditableGrid Props

PropTypeDefaultDescription
columns*EditableColumnDef<TData>[]Column definitions array.
data*TData[]The data array. Component is controlled — parent owns the data.
rowIdKey*keyof TData & stringProperty name used as unique row identifier (e.g. 'id', 'ssn').
onCellChange(rowId, columnId, newValue) => voidFired when a cell value is committed.
onRowChange(rowId, updatedRow) => voidFired with the full updated row after a cell commit.
onAddRow() => voidFired when the add-row button is clicked.
onDeleteRows(rowIds) => voidFired when rows are deleted (single or bulk).
enableAddRowbooleanfalseShow the add-row button at the bottom.
enableDeleteRowbooleanfalseShow per-row delete buttons and bulk delete.
enableRowSelectionbooleanfalseShow row selection checkboxes.
language"en" | "pt""en"UI language for labels and validation messages.
borderedbooleanfalseAdd borders to all cells.
compactbooleanfalseReduce cell padding and font size.
accentColorstringAccent color for checkboxes. Supports color names, #hex, or rgb().
classNamestringAdditional class name for the outer wrapper.

EditableColumnDef Fields

PropTypeDefaultDescription
columnId*keyof TData & stringData property key for this column.
title*stringColumn header label.
type*CellType"text" | "number" | "date" | "select" | "checkbox" | "textarea"
widthnumber | stringFixed column width (px or CSS string).
readonlybooleanfalseVisible but not editable (for ID columns).
optionsOptionItem[]Dropdown options. Required when type is 'select'.
validationValidationRulePer-cell validation: required, min, max, minLength, maxLength, pattern, custom.
placeholderstringPlaceholder text shown in empty cells and inputs.
formatter(value, row) => ReactNodeCustom display formatter for when the cell is not being edited.
aligned"left" | "center" | "right""left"Text alignment within the cell.

ValidationRule Fields

PropTypeDefaultDescription
requiredbooleanValue must not be empty.
minnumberMinimum number value.
maxnumberMaximum number value.
minLengthnumberMinimum string length.
maxLengthnumberMaximum string length.
patternRegExpRegex pattern for text validation.
custom(value, row) => string | nullCustom validation function. Return error message or null.