Skip to content

Inline Editing

WitTable uses an InlineEditor — a textarea overlay positioned over the active cell. Double-click a cell or press F2 to open the editor. Press Enter to commit the value, Escape to cancel, and Tab to commit and move to the next cell. Scrolling while editing auto-commits and closes the editor.

Live Demo
Double-click or press F2 to edit. Enter to commit, Escape to cancel.
Double-click or press F2 to edit a cell
View source code
EditingDemo.tsx
import { useState } from 'react';
import { WitTable } from '@witqq/spreadsheet-react';
import type { CellChangeEvent } from '@witqq/spreadsheet';
import { DemoWrapper } from './DemoWrapper';
import { generateEmployees, employeeColumns } from './generate-data';
import { useSiteTheme } from './useSiteTheme';
const data = generateEmployees(30);
const editableColumns = employeeColumns.map(col => ({ ...col, editable: true }));
export function EditingDemo() {
const { witTheme } = useSiteTheme();
const [lastEdit, setLastEdit] = useState('Double-click or press F2 to edit a cell');
const handleCellChange = (event: CellChangeEvent) => {
setLastEdit(`Edited row ${event.row}, col ${event.col}: "${event.oldValue}" → "${event.value}"`);
};
return (
<DemoWrapper title="Live Demo" description="Double-click or press F2 to edit. Enter to commit, Escape to cancel." height={440}>
<div style={{ display: 'flex', flexDirection: 'column', height: '100%' }}>
<div style={{ padding: '0.5rem 0.75rem', fontSize: '0.8rem', color: '#64748b', borderBottom: '1px solid #e2e8f0', flexShrink: 0 }}>
{lastEdit}
</div>
<div style={{ flex: 1 }}>
<WitTable
theme={witTheme}
columns={editableColumns}
data={data}
showRowNumbers
editable
onCellChange={handleCellChange}
style={{ width: '100%', height: '100%' }}
/>
</div>
</div>
</DemoWrapper>
);
}

Enable editing on the entire table and listen for changes:

import { WitTable } from '@witqq/spreadsheet-react';
function App() {
const [data, setData] = useState(initialData);
return (
<WitTable
columns={columns}
data={data}
editable={true}
onCellChange={(row, col, oldValue, newValue) => {
console.log(`Cell [${row},${col}]: ${oldValue}${newValue}`);
// Update your data source
}}
/>
);
}

Control which columns are editable through ColumnDef.editable:

const columns: ColumnDef[] = [
{ key: 'id', title: 'ID', editable: false },
{ key: 'name', title: 'Name', editable: true },
{ key: 'email', title: 'Email', editable: true },
{ key: 'role', title: 'Role', editable: false },
];

When the editor closes, the reason is provided as EditorCloseReason:

type EditorCloseReason = 'enter' | 'tab' | 'escape' | 'blur' | 'scroll';
  • enter — User pressed Enter (commits value, moves down)
  • tab — User pressed Tab (commits value, moves to next cell)
  • escape — User pressed Escape (cancels edit, restores original)
  • blur — Editor lost focus (commits value)
  • scroll — User scrolled while editing (auto-commits value)
MethodSignatureDescription
open(row: number, col: number) => voidOpen editor on cell
commitAndClose() => voidCommit current value and close
cancelAndClose() => voidDiscard changes and close
isEditing() => booleanWhether editor is currently open