Spreadsheet behavior for any table chrome. Headless hooks for inline edit, range select, fill handle, copy/paste — drop them on shadcn, Material, Fluent, or your own <table>. Or use the built-in <OGrid> component. React-first, MIT.
Documentation · Getting Started · API Reference · Migrate from AG Grid · Discord Community
Status: Active surface is React (Radix + Fluent UI). Vanilla JS, Material UI, Angular, and Vue variants are frozen on the
legacy/multiframeworkbranch — still on npm at their last shipped versions but no longer in active development. See Frozen adapters below.
Pick the React UI library you already use (Radix or Fluent) and get sorting, filtering, pagination, cell editing, spreadsheet selection, and the shared core grid model out of the box.
A set of headless React hooks that add spreadsheet behavior — inline edit, range select, fill handle, copy/paste, undo/redo, keyboard navigation — to any table chrome (shadcn <Table>, your own <table>, anything). MIT.
import {
useHeadlessGrid, useInlineEdit, useRangeSelection,
useFillHandle, useCellClipboard, useUndoRedo, useGridFocus,
} from "@alaarab/ogrid-react-radix";
const grid = useHeadlessGrid({ columns, data, getRowId: (r) => r.id });
const range = useRangeSelection({ rowCount: grid.rows.length, colCount: grid.columns.length });
const edit = useInlineEdit({ columns, getRowId: (r) => r.id, onCellEdit: applyEdit });
// ... render with shadcn <Table>, plain HTML, or whateverSee the Spreadsheet Demo Storybook for the full set of hooks combined on one page (~200 lines, copy-paste starter).
| OGrid | AG Grid Community | AG Grid Enterprise | |
|---|---|---|---|
| Spreadsheet selection | Built-in | No | $999/dev/year |
| Clipboard (copy/paste) | Built-in | No | $999/dev/year |
| Fill handle (drag to fill) | Built-in | No | $999/dev/year |
| Undo / Redo | Built-in | No | $999/dev/year |
| Context menu | Built-in | No | $999/dev/year |
| Status bar | Built-in | No | $999/dev/year |
| Side bar | Built-in | No | $999/dev/year |
| Cell editing | Built-in | Built-in | Built-in |
| Sorting & filtering | Built-in | Built-in | Built-in |
| Bundle size (gzip) | 44-61 KB | ~339 KB | ~339 KB+ |
| License | MIT (free) | MIT | Commercial |
| Cost | $0 | $0 | $999/dev/year |
Bundle size is what you actually install (core + framework adapter + UI layer). See the architecture section for per-setup sizes.
Data
- Sorting: click headers to sort, multi-column sort, custom comparators
- Filtering: text search, multi-select checkboxes, date range, people picker (client or server-side)
- Pagination: configurable page sizes, client-side or server-side via
IDataSource - Virtual scrolling: row and column virtualization for large datasets
- Web worker sort/filter: offload to a background thread with
workerSort: true - Server-side data:
IDataSourcepattern for remote pagination, sorting, filtering - Column types: built-in
text,numeric,date,booleanwith auto-formatting and filters
Editing
- Cell editing: inline text, select, checkbox, rich select, and custom popup editors
- Clipboard: Ctrl+C / X / V with multi-cell copy/paste, respects
valueFormatter/valueParser - Fill handle: drag to fill cells (Excel-style)
- Undo / redo: full edit history with Ctrl+Z / Ctrl+Y, batch operation support
- Premium inputs: optional calendar date picker and more via
@alaarab/ogrid-react-inputs
Selection & Navigation
- Spreadsheet selection: click-and-drag range selection with active cell highlight
- Row selection: single or multiple with Shift+click range support
- Keyboard navigation: Arrow keys, Tab, Enter, F2, Home/End, Ctrl+Home/End, Ctrl+Arrow (Excel-style)
- Cell references: Excel-style column letters (A, B, C...), row numbers, name box showing active cell
Columns
- Column groups: multi-row grouped headers with arbitrary nesting
- Column pinning: sticky left/right columns
- Column resize: drag column borders to resize
- Column chooser: show/hide columns via toolbar dropdown or sidebar panel
- Column state persistence: save/restore visibility, sort, order, widths, filters
UI
- Toolbar & layout: unified bordered container with primary toolbar, secondary
toolbarBelowrow, and footer - Side bar: toggle-able panel with Columns and Filters panels
- Context menu: right-click with copy, paste, cut, export, undo/redo and keyboard shortcuts
- Status bar: row count, filtered count, selection aggregations (sum, avg, min, max)
- Empty state: custom message or render function
- CSV export: one-click export with formatted values
Advanced
- Grid API:
ref-based imperative API forsetRowData,getColumnState,selectAll, etc. - Formula engine: 159 built-in functions, Excel-like formula bar, cell reference highlighting, cross-cell recalculation
- Editor integration (MCP):
@alaarab/ogrid-mcpconnects your IDE to OGrid docs and lets it read and control a running grid - CSS containment: automatic
contain: contenton cells,content-visibility: autoon off-screen rows - TypeScript strict: fully generic
<T>with strict mode, zeroanyleaks
@alaarab/ogrid-core (pure TS, zero deps)
└── @alaarab/ogrid-react hooks + headless components
├── ogrid-react-radix Radix UI views (default)
└── ogrid-react-fluent Fluent UI views
Core owns types and pure TypeScript utilities with zero dependencies. The React adapter (hooks + headless components) is the actively maintained surface. Frozen variants (Material UI, vanilla JS, Angular, Vue) live on the legacy/multiframework branch.
| Setup | Gzip |
|---|---|
| React + Radix | 54 KB |
| React + Fluent | 55 KB |
| AG Grid Community (comparison) | ~339 KB |
npm install @alaarab/ogrid-react-radiximport { OGrid, type IColumnDef } from '@alaarab/ogrid-react-radix';
const columns: IColumnDef<Employee>[] = [
{ columnId: 'name', name: 'Name', sortable: true, filterable: { type: 'text' } },
{ columnId: 'department', name: 'Department', filterable: { type: 'multiSelect' } },
{ columnId: 'salary', name: 'Salary', editable: true, type: 'numeric',
valueFormatter: (v) => `$${Number(v).toLocaleString()}` },
];
function App() {
return (
<OGrid
columns={columns}
data={employees}
getRowId={(e) => e.id}
editable
cellSelection
statusBar
/>
);
}Using Fluent UI? Change the import to
@alaarab/ogrid-react-fluent. Same API.
Need Material UI, vanilla JS, Angular, or Vue? See Frozen adapters — those packages still work at their last shipped versions but are no longer actively developed.
OGrid supports multiple editor types out of the box:
<OGrid
columns={[
{ columnId: 'name', name: 'Name', editable: true },
{ columnId: 'status', name: 'Status', editable: true,
cellEditor: 'select', cellEditorParams: { values: ['Active', 'Inactive'] } },
{ columnId: 'verified', name: 'Verified', editable: true, cellEditor: 'checkbox' },
]}
data={data}
getRowId={(r) => r.id}
editable
onCellValueChanged={(e) => console.log(e.columnId, e.oldValue, '->', e.newValue)}
/>Built-in editors: text (default), select, checkbox, date, richSelect, and custom popup editors via cellEditor component.
Access the imperative API via a ref for programmatic control:
const gridRef = useRef<IOGridApi<Product>>(null);
<OGrid ref={gridRef} data={products} columns={columns} getRowId={(r) => r.id} />
// Programmatic control
gridRef.current?.setRowData(newData);
gridRef.current?.setFilterModel({ status: ['Active'] });
gridRef.current?.selectAll();
// Save/restore column state (localStorage, database, etc.)
const state = gridRef.current?.getColumnState();
gridRef.current?.applyColumnState(savedState);Use the IDataSource interface for remote pagination, sorting, and filtering:
import type { IDataSource } from '@alaarab/ogrid-core';
const dataSource: IDataSource<Product> = {
async fetchPage({ page, pageSize, sort, filters }) {
const res = await fetch(`/api/products?page=${page}&pageSize=${pageSize}`);
return res.json(); // { items: Product[], totalCount: number }
},
async fetchFilterOptions(field) {
const res = await fetch(`/api/products/distinct/${field}`);
return res.json(); // string[]
},
};
<OGrid dataSource={dataSource} columns={columns} getRowId={(r) => r.id} />Main CI now stays fast with lint plus a browser smoke suite on every push, while the heavier verification workflows are run manually when you want a full release-grade pass.
| Package | npm | Peer Dependencies |
|---|---|---|
@alaarab/ogrid-core |
None | |
| React | ||
@alaarab/ogrid-react |
react, react-dom |
|
@alaarab/ogrid-react-radix |
react, react-dom |
|
@alaarab/ogrid-react-fluent |
+ @fluentui/react-components, @fluentui/react-icons |
UI packages re-export everything from their adapter (which re-exports from core), so one import is all you need.
Optional premium inputs (calendar date picker, rating, color picker, slider, tags) are available as @alaarab/ogrid-react-inputs.
The following packages remain published on npm at the version listed and the source lives on the legacy/multiframework branch, but they are no longer in the active build, test, release, or CI pipelines. They will not get framework-major upgrades or new features. Existing installs continue to work; for new projects, use the React Radix or React Fluent adapter.
| Frozen package | npm |
|---|---|
@alaarab/ogrid-react-material |
v2.9.1 (MUI v7; v9 dropped Typography props the adapter uses) |
@alaarab/ogrid-js, @alaarab/ogrid-js-inputs |
v2.9.1 (vanilla JS variant) |
@alaarab/ogrid-angular, -angular-material, -angular-primeng, -angular-radix, -angular-inputs |
v2.9.0 |
@alaarab/ogrid-vue, -vue-vuetify, -vue-primevue, -vue-radix, -vue-inputs |
v2.9.0 |
@alaarab/ogrid-mcp is a standalone MCP server that gives your IDE full access to OGrid documentation and lets it read and control a running grid in real time.
# One-time setup (any MCP-compatible editor)
npx -y @alaarab/ogrid-mcp
# Or add to your editor's MCP config
{
"mcpServers": {
"ogrid": { "command": "npx", "args": ["-y", "@alaarab/ogrid-mcp"] }
}
}Once connected, your editor can search and read the full OGrid documentation:
> Which filtering modes does OGrid support?
> Show me a server-side data source example
> How do I pin columns?
Available tools: search_docs, list_docs, get_docs, get_code_example, detect_version
Available resources: ogrid://quick-reference, ogrid://docs/{path}, ogrid://migration-guide
Add --bridge to let your editor read and control a running OGrid instance:
npx @alaarab/ogrid-mcp --bridgeThen connect your dev app with one useEffect:
import { connectGridToBridge } from '@alaarab/ogrid-mcp/bridge-client';
useEffect(() => {
const bridge = connectGridToBridge({
gridId: 'my-grid',
getData: () => data,
getColumns: () => columns,
onCellUpdate: (rowIndex, columnId, value) =>
setData(prev => prev.map((row, i) => i === rowIndex ? { ...row, [columnId]: value } : row)),
});
return () => bridge.disconnect();
}, [data]);Now your editor can inspect what's actually rendering, update cells, apply filters, and navigate pages while you watch the grid update live.
Bridge tools: list_grids, get_grid_state, send_grid_command
Note: The bridge is dev-only and localhost-only. Never run
--bridgein production.
See the MCP guide and live testing bridge guide for full documentation.
All packages run on bun:test with 2,768 tests total across the active surface:
| Package | Tests |
|---|---|
@alaarab/ogrid-core |
1,575 |
@alaarab/ogrid-react |
583 |
@alaarab/ogrid-react-radix |
153 |
@alaarab/ogrid-react-fluent |
153 |
@alaarab/ogrid-inputs |
133 |
@alaarab/ogrid-react-inputs |
132 |
@alaarab/ogrid-mcp |
39 |
React/DOM tests use @testing-library/react + happy-dom; cross-package source aliasing is handled via tsconfig paths. Playwright covers a fast smoke gate on every push plus a manual full matrix across the active example apps. Frozen variants live on the legacy/multiframework branch with their original Jest test suites.
OGrid uses Bun as the package manager and script runner. Install Bun 1.3+ first, then:
git clone https://github.com/alaarab/ogrid.git
cd ogrid
bun install
bun run build # Build all packages (Turborepo)
bun run test # Run all tests
bun run lint # Biome
bun run test:e2e:smoke # Browser merge gate (React Radix)
bun run test:e2e:docs # Built docs homepage verification
bun run test:e2e:matrix # Full browser matrix across active example apps
# GitHub Actions
# CI -> fast push/PR checks (lint + browser smoke)
# Full Verification -> manual full build/test matrix before release or larger merges
# Playwright Matrix -> manual browser parity pass across active example apps
# Storybook
bun run storybook:react-fluent # React Fluent UI (port 6006)
bun run storybook:react-radix # React Radix UI (port 6008)
# Documentation
bun run docs:dev # Docusaurus dev server
bun run docs:build # Build docs siteTests run natively on
bun:test(no Jest); shared setup atbun-test.setup.tsboots happy-dom, registers jest-dom matchers, and exposes the Jest globals so existing test syntax works unchanged. Published consumer packages remain plain npm — your users donpm install @alaarab/ogrid-react-radixexactly as before.
- Bun >= 1.3 (package manager + script runner + test runner)
- Node.js >= 18 (peer engine for published packages)
- Bun workspaces + Turborepo for monorepo management
Contributions are welcome. To get started:
- Fork the repository and create a feature branch.
- Make your changes following the project conventions (TypeScript strict, ESM-first, headless architecture).
- If your change affects UI, update both UI packages (
react-radix+react-fluent) to maintain parity. - Add or extend tests. Use the shared test factories in
@alaarab/ogrid-react/testingso both UI packages get coverage. - Run the full verification suite before submitting:
bun run build && bun run test && bun run lint && bun run test:e2e:smoke- Open a pull request with a clear description of what changed and why.
See ARCHITECTURE.md for detailed architecture documentation and conventions.
Built by Ala Arab