edit-table-pro
v0.1.1
Published
High-performance editable table for React — virtual scroll, validation, undo/redo, fill handle, zero runtime dependencies
Downloads
13
Maintainers
Readme
edit-table-pro
Editable table for React. Built for real datasets — 50,000+ rows, fill handle, undo/redo, paste from Excel, zero runtime dependencies.
Table of Contents
- 🧠 The Story
- ⚡ Quick Start
- 🚫 This is not AG Grid
- 🤔 Why not react-table / Handsontable / AG Grid?
- ✨ Features
- ⌨️ Keyboard Shortcuts
- 🎨 Theming
- 📖 Documentation
- 🤝 Contributing
- 🗺️ Roadmap
- 🏗️ How It Works
- 🙏 Contributors
- 📄 License
- 🇻🇳 Tiếng Việt
🧠 The Story
Every React project that handles real data eventually hits the same wall.
You start with a read-only table. Then a PM asks: "Can users edit inline?" You wire up a few inputs. It works. Then: "Can we paste from Excel?" You start parsing \t-separated strings. Then: "Can we validate before saving?" You add error state. Then: "Undo when they make a mistake?" You realize you need a command stack.
By this point you're maintaining a mini spreadsheet engine — inside your product code.
Most teams reach for AG Grid Community or Handsontable at this point. Both work. But AG Grid Community gives you the engine and nothing else — every feature is configuration XML. Handsontable is jQuery-era architecture adapted to React. And both pull in a dependency tree you have to audit, maintain, and ship to users.
edit-table-pro is the third option.
It ships what you actually need out of the box: virtual scroll for 50k+ rows, fill handle (with smart numeric/date series), multi-cell selection, paste from Excel/Sheets, per-column validation, side effects, undo/redo, row selection, column resize, CSV export. All of it. One npm install. Zero runtime dependencies beyond React.
Not a toy. Not a prototype. A component you can drop into production on Monday.
⚡ Quick Start
npm install edit-table-proPeer dependencies: React ≥ 18, React DOM ≥ 18
Import the stylesheet once in your app entry:
import 'edit-table-pro/style.css'import { EditableTable } from 'edit-table-pro'
import type { ColDef } from 'edit-table-pro'
import 'edit-table-pro/style.css'
type Product = {
id: string
name: string
price: string
stock: string
}
const columns: ColDef<Product>[] = [
{ key: 'name', type: 'text', header: 'Name', width: 200 },
{ key: 'price', type: 'number', header: 'Price', width: 100,
validate: (v) => Number(v) >= 0 ? { ok: true } : { ok: false, error: 'Must be ≥ 0' } },
{ key: 'stock', type: 'number', header: 'Stock', width: 100 },
]
const data: Product[] = [
{ id: '1', name: 'Widget A', price: '9.99', stock: '100' },
{ id: '2', name: 'Widget B', price: '14.99', stock: '50' },
]
export default function App() {
return (
<EditableTable
columns={columns}
initialData={data}
getRowId={(row) => row.id}
height={400}
/>
)
}Note: All cell values are
string. Numbers, dates, and booleans are stored as strings and formatted/validated per column — no surprises at the data layer.
If this saved you time — ⭐ star it. It helps others find it.
🚫 This is not AG Grid
edit-table-pro is not a grid framework. It is not a data platform. It is not configurable XML.
It is a React component for editing tabular data — validation, side effects, undo/redo, and Excel-like UX baked in.
Grid frameworks work like this:
install → configure grid options → register modules → apply license → build features yourselfedit-table-pro works like this:
npm install → define columns → render → doneThree things this library has that alternatives don't ship together:
Fill handle with smart series detection — drag to fill like Excel. Single value → copy. Two numbers → increment by delta. Two dates → increment by day/month/year. Automatically. No config.
Edit session architecture — every cell has its own edit session. Virtual scroll doesn't clear what you've typed when a row scrolls off screen. Your input is always safe.
Zero runtime dependencies — no lodash, no date-fns, no axios. The only peer dependencies are React and React DOM — already in your project. Nothing new to audit, nothing new to bundle.
🤔 Why not react-table / Handsontable / AG Grid?
Wrong tradeoff for the job.
| | edit-table-pro | react-table / TanStack | AG Grid Community | Handsontable | | --- | --- | --- | --- | --- | | Drop-in editing UX | ✅ | ❌ headless, build it yourself | ⚠️ requires module config | ✅ | | Virtual scroll (50k+ rows) | ✅ | ✅ with plugin | ✅ | ✅ | | Fill handle | ✅ | ❌ | ❌ Community | ✅ paid | | Paste from Excel | ✅ | ❌ | ✅ | ✅ | | Undo / Redo | ✅ | ❌ | ❌ Community | ✅ paid | | Side effects pipeline | ✅ | ❌ | ❌ | ❌ | | Zero runtime deps | ✅ | ✅ | ❌ | ❌ | | React 18 native | ✅ | ✅ | ⚠️ adapter | ⚠️ wrapper | | MIT license | ✅ | ✅ | ✅ | ⚠️ non-commercial | | Bundle size (approx) | ~18 KB gz | ~14 KB gz | ~100 KB+ gz | ~100 KB+ gz |
The real difference:
react-table / TanStack Table: Headless — you design and build every interactive UI. Right call for read-only displays and custom designs. Wrong call when you need editing to just work.
AG Grid Community: The full engine — but editing, fill handle, and undo are Enterprise features. And you're writing column definitions in JSON objects, not TypeScript.
Handsontable: The original spreadsheet library — but it's canvas-based rendering adapted to React, non-commercial license for free tier, and a bundle that ships everything whether you use it or not.
edit-table-pro: One component. Editing works. Fill handle works. Undo works. Tree-shakeable. MIT.
✨ Features
| Feature | Description |
| --- | --- |
| Virtual scroll | Renders only visible rows — 50,000+ rows at 60fps |
| Edit session | Per-cell session survives virtual scroll unmount — no lost input |
| Inline validation | Sync validation per cell, tooltip error on blur |
| Side effects | Async callbacks on change / blur — auto-save, dependent fields, debounce, abort |
| Undo / Redo | Ctrl+Z / Ctrl+Y, batch undo for fill and paste operations |
| Fill handle | Drag to fill down/up — copy, numeric series, ISO date series |
| Multi-cell selection | Click+drag or Shift+click range, then fill all columns at once |
| Paste from Excel/Sheets | TSV paste maps to the correct columns automatically |
| Row selection | Checkbox column with onSelectionChange callback |
| Column resize | Drag column header edge to resize |
| Readonly cells | col.editable: false → read-only display per column |
| Custom render | col.render for badges, buttons, links inside cells |
| CSV export | One-call export with BOM prefix for Excel UTF-8 compatibility |
| Theming | CSS variable overrides or theme prop |
| Zero runtime deps | No lodash, no axios, no date library — just React |
⌨️ Keyboard Shortcuts
| Key | Action |
| --- | --- |
| Tab / Enter | Move to next cell |
| Shift+Tab | Move to previous cell |
| Arrow keys | Navigate between cells |
| Escape | Cancel edit, restore committed value |
| Ctrl+Z | Undo (including multi-cell fill) |
| Ctrl+Y / Ctrl+Shift+Z | Redo |
| Ctrl+D | Fill down one row |
| Ctrl+R | Fill right one column |
🎨 Theming
Override CSS variables anywhere in your stylesheet:
.et-root {
--et-color-primary: #52c41a;
--et-color-bg-header: #f6ffed;
--et-color-row-hover: rgba(82,196,26,0.04);
--et-font-size: 13px;
--et-border-radius: 4px;
}Or use the theme prop:
<EditableTable
theme={{ colorPrimary: '#52c41a', colorBgHeader: '#f6ffed' }}
...
/>📖 Documentation
| Guide | Contents | | --- | --- | | Getting Started | Step-by-step setup, first working table | | ColDef Reference | Every column definition field explained | | Validation | Sync validation, cross-column rules, error display | | Side Effects | Auto-save, dependent fields, abort & debounce | | Fill & Selection | Fill handle, multi-cell select, paste | | Row Management | Add rows, row selection, batch append | | Export & Submit | CSV export, collecting dirty rows, submit flow | | Custom Render | Buttons, badges, and custom cell content | | Performance Guide | Benchmarks, sweet spots, pitfalls | | Limitations | What it does not support and when to use alternatives |
🤝 Contributing
See CONTRIBUTING.md for setup notes and the PR checklist.
The library is ~1,500 lines of TypeScript split into a pure core (src/core/) and React adapters (src/react/). The core has zero React dependency — fully testable in isolation. You can read the entire engine in an hour.
If you've ever wanted to contribute to open source but felt intimidated by monorepos and 47-step setup guides — this is approachable.
Good first contributions:
| Issue | Difficulty | What |
| --- | --- | --- |
| #1 — onCellClick callback | Easy | Fire a callback when any cell is clicked |
| #2 — placeholder per column | Easy | Show placeholder text in empty cells |
| #3 — autoFocus on mount | Easy | Focus the first editable cell when table renders |
| #4 — improved dark mode CSS | Easy | CSS-only, no JS required |
| #5 — horizontal fill drag | Medium | Drag fill handle horizontally across columns |
How to contribute:
- Fork the repo
npm install— only dev dependencies, no global tools needednpm run dev— Vite dev server with live examples- Edit
src/— TypeScript, strict mode npm run typecheck && npm run check— must pass before PR- Open a PR with a short description of what changed and why
🗺️ Roadmap
These are things not yet built. Any of them would make a great PR — claim one in Issues:
- [x] Virtual scroll — 50k+ rows at 60fps
- [x] Edit session persistence — input survives scroll unmount
- [x] Fill handle — drag down/up with series detection
- [x] Multi-cell selection — click+drag, Shift+click, multi-col fill
- [x] Paste from Excel — TSV paste with column mapping
- [x] Undo / Redo — batch undo for fill and paste
- [ ] Horizontal fill drag — drag fill handle left/right across columns
- [ ] Frozen/pinned columns — lock leftmost columns during horizontal scroll
- [ ] Row drag to reorder — drag rows up/down to reorder
- [ ] Column sorting — click header to sort asc/desc
- [ ] Right-click context menu — copy, paste, fill, clear
- [ ] Auto-scroll on drag edge — scroll when dragging fill handle near viewport edge
- [ ]
numbercell type — right-aligned with numeric keyboard on mobile
Have an idea not on this list? Open an issue or just build it.
🏗️ How It Works
src/
├── core/ ← Pure TypeScript, zero React — fully testable
│ ├── engine/ ← commitCell, validation pipeline, sideEffect runner
│ ├── session/ ← EditSessionStore (external store, useSyncExternalStore)
│ ├── virtual/ ← visible range + overscan calculation
│ ├── history/ ← undo/redo command stack
│ ├── fill/ ← detectSeriesType, generateFillValues
│ ├── dirty/ ← dirty row tracker (original vs current snapshot)
│ ├── export/ ← exportCsv with BOM
│ └── types.ts ← ColDef, EditSession, CellPos, CellSelectionRange ...
└── react/ ← React adapters
├── hooks/ ← useEditableTable, useEditSession
├── components/ ← EditableTable, Cell, HeaderRow, VirtualBody, FillHandle
└── context/ ← TableContext (refs shared down to cells)Key architecture decisions:
- No React state for data —
rowsDataRef,dirtyRowsRef, andeditSessionStoreare refs/external stores. Only UI state (scroll position, fill preview) goes throughuseState. useSyncExternalStore— each cell subscribes to its own session key. Only the cell whose session changes re-renders. 50k rows, one keystroke, one re-render.- Pointer Events, not Mouse Events — fill handle uses
setPointerCapture. Chrome's native drag mode blocksmouseup, breaking drag-end. Pointer Events don't.
🙏 Contributors
Thanks to everyone who has improved this project:
zzgiabaozzbui — Original author
Your name could be here. See Contributing ↑
📄 License
MIT — do whatever you want, just keep the copyright notice. See LICENSE.
🇻🇳 Tiếng Việt
Câu chuyện
Mọi dự án React xử lý dữ liệu thật đều đụng vào một bức tường quen thuộc.
Ban đầu chỉ là table read-only. Rồi PM hỏi: "User edit inline được không?" Bạn thêm vài input. Chạy được. Rồi: "Paste từ Excel được không?" Bạn bắt đầu parse chuỗi \t. Rồi: "Validate trước khi lưu?" Bạn thêm error state. Rồi: "Undo khi nhập nhầm?" Bạn nhận ra cần một command stack.
Lúc này bạn đang tự bảo trì một mini spreadsheet engine — ngay bên trong code sản phẩm.
edit-table-pro là lựa chọn thứ ba. Những thứ cần thiết đã có sẵn trong hộp: virtual scroll cho 50k+ rows, fill handle với nhận dạng series thông minh, multi-cell selection, paste từ Excel/Sheets, validation per-column, side effects, undo/redo, row selection, column resize, CSV export. Tất cả. Một lần npm install. Zero runtime dependencies ngoài React.
Cài đặt nhanh
npm install edit-table-proimport { EditableTable } from 'edit-table-pro'
import 'edit-table-pro/style.css'
<EditableTable
columns={columns}
initialData={data}
getRowId={(row) => row.id}
height={400}
/>Tại sao không dùng AG Grid / react-table / Handsontable?
| | edit-table-pro | react-table | AG Grid Community | Handsontable | | --- | --- | --- | --- | --- | | Editing UX sẵn dùng | ✅ | ❌ tự build | ⚠️ cần config module | ✅ | | Virtual scroll (50k+ rows) | ✅ | ✅ plugin | ✅ | ✅ | | Fill handle | ✅ | ❌ | ❌ Enterprise | ✅ trả phí | | Paste từ Excel | ✅ | ❌ | ✅ | ✅ | | Undo / Redo | ✅ | ❌ | ❌ Enterprise | ✅ trả phí | | Zero runtime deps | ✅ | ✅ | ❌ | ❌ | | MIT license | ✅ | ✅ | ✅ | ⚠️ phi thương mại |
Đóng góp
src/core/ ← Pure TypeScript, zero React — đọc và test độc lập
src/react/ ← React adaptersFork → npm install → npm run dev → sửa → npm run typecheck && npm run check → PR.
Xem good first issues để tìm việc cụ thể.
Roadmap
- [x] Virtual scroll, fill handle, multi-cell selection, paste, undo/redo
- [ ] Horizontal fill drag
- [ ] Frozen/pinned columns
- [ ] Row drag to reorder
- [ ] Column sorting
- [ ] Context menu
Nhận issue tại đây hoặc tự build và gửi PR.
Made by zzgiabaozzbui · ⭐ Star if useful · 🐛 Report a bug
