Excel-like grid component built with React, with editors, keyboard navigation, copy & paste, and the like
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Cell editing functionality providing built-in editors and infrastructure for custom cell editing components with keyboard navigation support.
Pre-built editor components for common cell editing scenarios.
const editors = {
/** Simple text input editor for string values */
SimpleTextEditor: React.ComponentType<EditorProps>;
/** Checkbox editor for boolean values */
CheckboxEditor: React.ComponentType<EditorProps>;
/** Base class for creating custom editors */
EditorBase: React.ComponentType<EditorProps>;
};
interface EditorProps {
/** Current cell value to edit */
value: any;
/** Function to handle key down events */
onKeyDown: (event: KeyboardEvent) => void;
/** Function called when editor loses focus */
onBlur: () => void;
/** Function to commit the edited value */
commit: () => void;
/** Column definition for the cell being edited */
column: Column;
/** Complete row data object */
row?: any;
/** DOM element where editor should be rendered */
editorPortalTarget?: Element;
}Basic text input editor for editing string values with Enter/Escape key support.
/**
* Simple text input editor for string cell values
* Commits on Enter key, cancels on Escape key
*/
const SimpleTextEditor: React.ComponentType<EditorProps>;Usage Example:
import ReactDataGrid, { editors } from 'react-data-grid';
const columns = [
{ key: 'id', name: 'ID' },
{
key: 'name',
name: 'Name',
editor: <editors.SimpleTextEditor />,
editable: true
},
{
key: 'description',
name: 'Description',
editor: <editors.SimpleTextEditor />,
editable: true
}
];
// The editor will automatically be used when editable: true is set
<ReactDataGrid
columns={columns}
rowGetter={i => rows[i]}
rowsCount={rows.length}
minHeight={400}
enableCellSelect={true}
onGridRowsUpdated={handleRowUpdate}
/>Checkbox editor for boolean values with immediate commit on click.
/**
* Checkbox editor for boolean cell values
* Commits immediately when checkbox state changes
*/
const CheckboxEditor: React.ComponentType<EditorProps>;Usage Example:
import ReactDataGrid, { editors } from 'react-data-grid';
const columns = [
{ key: 'id', name: 'ID' },
{ key: 'name', name: 'Name' },
{
key: 'active',
name: 'Active',
editor: <editors.CheckboxEditor />,
editable: true
},
{
key: 'verified',
name: 'Verified',
editor: <editors.CheckboxEditor />,
editable: true
}
];Base class providing common editor functionality for creating custom editors.
/**
* Base class for custom cell editors
* Provides common editor lifecycle and keyboard handling
*/
class EditorBase extends React.Component<EditorProps> {
/** Get the current input value */
getValue(): any;
/** Get the input node for focus management */
getInputNode(): HTMLElement;
/** Check if the current value is valid */
isSelectAllWhenEditingEnabled(): boolean;
/** Handle keyboard events (Enter, Escape, Tab) */
onKeyDown(event: KeyboardEvent): void;
}Creating custom editors by extending EditorBase or implementing the EditorProps interface.
/**
* Interface for custom editor components
* Must implement these methods for proper grid integration
*/
interface CustomEditor extends React.Component<EditorProps> {
/** Return the current editor value */
getValue(): any;
/** Return the DOM node to focus */
getInputNode(): HTMLElement;
/** Handle special key combinations */
onKeyDown?(event: KeyboardEvent): void;
}Custom Editor Example:
import React from 'react';
import { editors } from 'react-data-grid';
// Custom dropdown editor
class DropdownEditor extends editors.EditorBase {
constructor(props) {
super(props);
this.state = { value: props.value };
}
getValue() {
return this.state.value;
}
getInputNode() {
return this.select;
}
render() {
const options = this.props.column.options || [];
return (
<select
ref={node => this.select = node}
value={this.state.value}
onChange={e => this.setState({ value: e.target.value })}
onBlur={() => this.props.onCommit(this.state.value)}
autoFocus
>
{options.map(option => (
<option key={option.value} value={option.value}>
{option.label}
</option>
))}
</select>
);
}
}
// Usage in column definition
const columns = [
{ key: 'id', name: 'ID' },
{ key: 'name', name: 'Name' },
{
key: 'status',
name: 'Status',
editor: <DropdownEditor />,
editable: true,
options: [
{ value: 'active', label: 'Active' },
{ value: 'inactive', label: 'Inactive' },
{ value: 'pending', label: 'Pending' }
]
}
];Column-level configuration for enabling and customizing cell editing.
interface EditableColumn extends Column {
/** Enable editing for this column */
editable: boolean;
/** Custom editor component (optional, defaults to SimpleTextEditor) */
editor?: React.ComponentType<EditorProps>;
/** Additional options passed to custom editors */
[key: string]: any;
}Events related to cell editing lifecycle and data updates.
interface EditingEvents {
/** Called when cell editing results in data updates */
onGridRowsUpdated?: (event: GridRowsUpdatedEvent) => void;
/** Called before a cell becomes editable */
onCheckCellIsEditable?: (event: CheckCellEditableEvent) => boolean;
/** Called just before editing begins */
onBeforeEdit?: (event: BeforeEditEvent) => void;
}
interface GridRowsUpdatedEvent {
/** Starting row index for the update */
fromRow: number;
/** Ending row index for the update */
toRow: number;
/** Object containing the updated values */
updated: { [columnKey: string]: any };
/** Type of update action that occurred */
action: 'CELL_UPDATE' | 'COLUMN_FILL' | 'COPY_PASTE' | 'CELL_DRAG';
}
interface CheckCellEditableEvent {
/** Row data object */
row: any;
/** Column being edited */
column: Column;
/** Row index */
rowIdx: number;
}
interface BeforeEditEvent {
/** Row index being edited */
rowIdx: number;
/** Column being edited */
column: Column;
/** Row data object */
row: any;
}Advanced Editing Example:
import ReactDataGrid, { editors } from 'react-data-grid';
const EditableGrid = () => {
const [rows, setRows] = useState(initialData);
const handleGridRowsUpdated = ({ fromRow, toRow, updated, action }) => {
console.log('Update action:', action);
const newRows = rows.slice();
for (let i = fromRow; i <= toRow; i++) {
newRows[i] = { ...newRows[i], ...updated };
}
setRows(newRows);
};
const checkCellEditable = ({ row, column, rowIdx }) => {
// Only allow editing if row is not locked
return !row.locked;
};
const beforeEdit = ({ rowIdx, column, row }) => {
console.log(`Starting to edit ${column.key} in row ${rowIdx}`);
};
const columns = [
{ key: 'id', name: 'ID' },
{
key: 'name',
name: 'Name',
editable: true,
editor: <editors.SimpleTextEditor />
},
{
key: 'active',
name: 'Active',
editable: true,
editor: <editors.CheckboxEditor />
},
{
key: 'category',
name: 'Category',
editable: true,
editor: <CustomDropdownEditor />
}
];
return (
<ReactDataGrid
columns={columns}
rowGetter={i => rows[i]}
rowsCount={rows.length}
minHeight={500}
enableCellSelect={true}
onGridRowsUpdated={handleGridRowsUpdated}
onCheckCellIsEditable={checkCellEditable}
onBeforeEdit={beforeEdit}
/>
);
};Built-in keyboard shortcuts for editing and navigation.
Editors are rendered in DOM portals to avoid z-index and overflow issues.
interface EditorPortalConfig {
/** DOM element where editor portals should be mounted */
editorPortalTarget?: Element;
}Usage Example:
// Custom portal target
const customPortalTarget = document.getElementById('editor-container');
<ReactDataGrid
columns={columns}
rowGetter={i => rows[i]}
rowsCount={rows.length}
minHeight={400}
editorPortalTarget={customPortalTarget}
/>Install with Tessl CLI
npx tessl i tessl/npm-react-data-grid@6.1.1