This file is auto-loaded by Claude Code and other AI coding assistants. It provides the orientation needed to work in this codebase without exploring files first.
@opencorestack/opengridx — a high-performance React DataGrid component library.
- Language: TypeScript 5.9 strict mode. Zero
any, zeroeslint-disable. - Framework: React 19
- Tests: Vitest 4 +
@testing-library/react(renderHookfor hooks, component tests for UI) - Build: Vite (library mode).
npm run buildproducesdist/opengridx.es.jsanddist/opengridx.umd.js. - Lint:
npm run lint(ESLint). Must pass before every commit. - Current version: 2.0.4
Props enter DataGrid.tsx (the orchestration layer — no logic lives here, only hook calls and JSX).
DataGridProps
│
├─ useGridControlledState — normalises controlled/uncontrolled prop pairs
│ (sort, pagination, selection, column visibility, pivot, aggregation)
│
├─ useGridRowPipeline — filter → sort → paginate → split pinned rows
│
├─ useGridColumns — inject hierarchy renderers; resolve order/visibility
│ reads rowMetaMap (from useTreeData / useRowGrouping) instead of row._* fields
│
├─ useGridVirtualization — compute render window (which rows/columns are visible)
│
├─ useGridVisibleRows — merge pinned + virtual center → { row, rowIndex }[]
│
└─ JSX renders:
Header, GridVirtualRows, GridPinnedRows, Pagination, GridAggregationFooter
Hierarchy (tree data, row grouping) is handled by useTreeData / useRowGrouping. They produce flat renderable row arrays with internal _* fields injected (runtime shim, still present as of v2.0.4 — deprecated, deferred to a future major version) and a rowMetaMap: Map<GridRowId, GridRowMeta> that is the clean typed API.
| File | Purpose |
|---|---|
lib/types/index.ts |
All public types: DataGridProps, GridColDef, GridRowModel, GridRowMeta, GridLocaleText, GridRenderCellParams, etc. |
lib/components/DataGrid/DataGrid.tsx |
Orchestration only — hooks + JSX, no business logic |
lib/hooks/core/ |
Core pipeline hooks (always active): useGridControlledState, useGridRowPipeline, useGridColumns, useGridVirtualization, useGridVisibleRows, useGridScrollSync, useGridKeyboardNavigation, useLayout |
lib/hooks/features/ |
Opt-in feature hooks: useAggregation, usePivot, useGridEditing, useGridSpanning, useGridDataSource, useGridClipboard |
lib/hooks/useTreeData.ts |
Tree-data hierarchy — flat row array + rowMetaMap |
lib/hooks/useRowGrouping.ts |
Row-grouping hierarchy — flat row array + rowMetaMap |
lib/components/Cell/Cell.tsx |
Cell render — invokes renderCell, wraps with CellErrorBoundary |
lib/components/Cell/CellErrorBoundary.tsx |
Class error boundary wrapping renderCell output |
lib/utils/filtering/ |
Client-side filter operators |
lib/utils/sorting/ |
Client-side sort comparators |
| Task | Where |
|---|---|
| New filter operator for a column type | lib/utils/filtering/filtering.ts + types/index.ts |
| New feature (aggregation, pivot, etc.) | New hook in lib/hooks/features/, consumed by DataGrid.tsx |
| New core pipeline stage | New hook in lib/hooks/core/, added to DataGrid.tsx |
| New component (slot, overlay, etc.) | lib/components/<Name>/ |
New public prop on DataGrid |
Add to DataGridProps in lib/types/index.ts, destructure in DataGrid.tsx |
| New column type | GridColType union in lib/types/index.ts, operators in lib/utils/filtering/filtering.ts |
| New slot | Add to GridSlots in lib/types/index.ts, wire in DataGrid.tsx via slots?.mySlot |
- CSS classes:
ogx__BEM prefix (e.g.ogx__cell,ogx__cell--focused) - CSS variables:
--ogx-*(e.g.--ogx-row-height,--ogx-color-primary) - Hook names:
use-grid-*for core hooks,use*for feature hooks - Exported types:
Grid*prefix (e.g.GridColDef,GridRowMeta,GridLocaleText) - Internal fields still on row at runtime (deprecated shim, not yet removed — was mistakenly documented as removed in v2.0):
_hasChildren,_treeDepth,_isExpanded,_groupingField,_groupingValue,_descendantCount,_isGroupRow
Hierarchy metadata (hasChildren, treeDepth, groupingField, etc.) lives in a Map<GridRowId, GridRowMeta> returned by useTreeData/useRowGrouping, not on the row object. Access it in renderCell via params.rowMeta.
The underscore fields remain on the row object at runtime — this shim was carried through v1.x and is still present in v2.0.4; the injection was never actually removed in v2.0 despite earlier drafts of this file and docs/roadmap.md claiming otherwise. Removal is deferred to a future major version. When it happens, delete the _hasChildren = ... assignments in useTreeData.ts and useRowGrouping.ts. Until then, don't write code that assumes the underscore fields are absent.
Full doc: docs/architecture/grid-row-meta.md
- Test files are co-located with the file they test:
useGridRowPipeline.test.tslives inlib/hooks/core/ - Import pattern:
import { describe, it, expect, vi } from 'vitest'+import { renderHook, act } from '@testing-library/react' - Hook tests use
renderHook(() => useMyHook(params))— no DOM needed for pure hooks - Component tests use
renderfrom@testing-library/react - Run all tests:
npx vitest run - Run a single file:
npx vitest run lib/hooks/core/useGridRowPipeline.test.ts
| Content | Location |
|---|---|
| Component public API (props, slots, events) | docs/components/<name>.md |
| Internal hook architecture | docs/architecture/<hook-name>.md |
| Feature guides (usage patterns, code examples) | docs/features/<feature>.md |
| Full public API reference | docs/API_REFERENCE.md |
| Roadmap and feature status | docs/roadmap.md |
npm run lint && npm run buildmust pass after every change- Zero
eslint-disableor@ts-ignore— fix the root cause - Zero
any— useunknownor explicit interfaces - Never add
Co-Authored-ByAI attribution to commit messages
The following props/types existed in v1.x but had no runtime implementation. They have been removed from the public TypeScript types:
| Removed | Type | Reason |
|---|---|---|
onPinnedRowsChange |
DataGridProps |
No pin/unpin-row UI exists; callback was never called |
onRowGroupingModelChange |
DataGridProps |
No drag-to-group UI; callback was never called |
description |
GridColDef |
Not read anywhere in the grid |
density?: 'compact' | 'standard' | 'comfortable' now controls effectiveRowHeight (compact=32, standard=rowHeight, comfortable=72) via CSS --ogx-row-height. Previously the prop was accepted but silently discarded.
Both props are now wired in handleRowClick. disableRowSelectionOnClick suppresses click-to-select; disableMultipleRowSelection caps selection to a single row.
When rowGroupingModel is active, passing groupingColDef now creates a dedicated synthetic __group__ column at position 0, auto-pinned left. Previously the prop was accepted but had no runtime effect.
Columns with groupable: false are now skipped when building the grouping tree in useRowGrouping. Previously this flag was silently ignored.
groupingValueFormatter?: (params: { field: string; value: unknown }) => stringCustomizes the label for group-header rows at that level. Falls back to "${field}: ${value}" when omitted. The formatted string flows through GridRowMeta.groupLabel so useGridColumns picks it up for rendering.
Per-column availableAggregationFunctions?: string[] now gates which aggregation functions are computed in useAggregation. If the current aggregationModel entry for a field uses a function not in that list, the aggregation is skipped for that field.
Shift-clicking a column header now appends to (or removes from) sortModel rather than replacing it. The sort priority badge (1, 2, 3…) appears next to the sort arrow when more than one sort key is active. Plain click still replaces with a single-key sort.
GridApi.getGroupedExportRows()— new method returning a flatGridGroupedExportRow[]ordered list by traversing the active row-grouping tree (group-header → children → subtotal → grand-total). Returnsnullwhen row grouping is not active.GridGroupedExportRowtype — public interface for each entry:type(group-header | leaf | group-subtotal | grand-total),depth, optionalgroupField,groupValue,aggregatedValues,row.- Grouped export across all formats —
exportToCsv,exportToExcel,exportToJson,printGrid,exportToPdfall acceptgroupedRows?: GridGroupedExportRow[]; flat behavior unchanged when absent.
hideable: falsecolumns excluded from Columns panel —ColumnVisibilityPanelnow filters out columns withhideable: falseby default, removing the permanently-disabled rows that added visual noise. Columns still render in the grid body and exports unchanged.GridToolbarProps.showNonHideableColumns— new optional boolean prop. Passtrueto restore the old behavior (show non-hideable columns as disabled rows in the panel). Default:false.
CellErrorBoundaryCellRenderTarget pattern —renderFnis now called inside a module-scopeCellRenderTargetchild component so the throw happens in a descendant; boundaries cannot catch errors in their ownrender()resetKey={row}— error boundary resets when the row object reference changes (not just the cell value), so "Restore" correctly clears error state after fresh row objects are providedgetAllFilteredRows()API — newGridApimethod returning all filtered+sorted rows regardless of pagination; use for full-dataset exports- PDF aggregation footer —
PdfExportDemonow computes the aggregation directly from exported rows (bypassesuseEffect-basedgetAggregationResult); footer now reliably appears with correct values - PDF footer text color — aggregation footer row text is now explicitly black (
[0,0,0]) instead of inheriting the default (which could render invisible against the light gray fill) exportToPdfstandalone API — usesautoTable(doc, opts)standalone function instead ofdoc.autoTable(opts)to avoid unreliable ESM prototype patching
exportToPdf— native PDF export via optional peer depsjspdf+jspdf-autotable; lazy-loaded, zero bundle impact for non-PDF consumersPdfExportOptions— 12-field interface: fileName, title, logoUrl, orientation, selectedRows, aggregationResult, aggregationModel, filterModel, alternateRowColor, headerBackgroundColor, headerTextColor, fontSizeCellErrorBoundaryfix — changed torenderFnprop so the boundary callsrenderCellinside its ownrender(); previously the throw occurred in the parent before the boundary could catch it- GitHub Pages SPA routing — deploy workflow now copies
404.htmlso direct URL access to demo routes works
GridRowMeta— hierarchy metadata moved offGridRowModelintoMap<GridRowId, GridRowMeta>; exposed viaparams.rowMetainrenderCellCellErrorBoundary—renderCellerrors now caught per-cell; grid continues renderingGridLocaleText/localeTextprop — all pagination strings are now overrideable for i18n- Duplicate DOM ID fix —
Rowcheckbox andFilterPanelinputs now useuseId()(wasogx-select-row-${row.id}, caused duplicates with two grids on one page)