npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@itsmemyk/react-tree-grid

v0.5.2

Published

High-performance Grid, Tree, and TreeGrid components for React

Downloads

103

Readme

react-tree-grid

The best open-source alternative to DHTMLX TreeGrid — high-performance Grid, Tree, and TreeGrid components for React 18+, with zero dependencies and a feature-complete API.

npm TypeScript License: MIT

DHtmlx Showcase

Documentation →
Guides, API reference, and examples.

Live demo →
Full-featured showcase: tree rows, drag-and-drop reorder, multi-select, inline edit, header filters, footer sums, avatar columns, status badges, and signed balance.


  • Zero runtime dependencies — React is the only peer
  • Full TypeScript support with generics
  • Tree-shakeable sub-path exports
  • Virtual scrolling for large datasets
  • Light and dark themes via ThemeProvider
  • CSS custom properties (--react-tree-grid-*) for token-level theming
  • Frozen rows and columns (left, right, top, bottom splits)
  • Multi-level column headers and footer aggregates (sum, avg, count, min, max)
  • Inline cell editing with built-in editor types (input, select, combo, datePicker, multiselect)
  • Row and column drag-and-drop reorder
  • Column sort, resize, and drag-panel grouping
  • Row grouping with aggregates for TreeGrid
  • Multi-select with keyboard navigation
  • Header filters (inputFilter, selectFilter, comboFilter)
  • Cell tooltips and custom cell renderers via template

Table of Contents

Installation

# npm
npm install @itsmemyk/react-tree-grid

# pnpm
pnpm add @itsmemyk/react-tree-grid

# yarn
yarn add @itsmemyk/react-tree-grid

# bun
bun add @itsmemyk/react-tree-grid

Quick Start

Grid

import { Grid } from 'react-tree-grid/grid'
import { ThemeProvider } from 'react-tree-grid'

const columns = [
  { id: 'name', header: [{ text: 'Name' }], width: 180 },
  { id: 'email', header: [{ text: 'Email' }], width: 240 },
]

const data = [
  { id: '1', name: 'Alice', email: '[email protected]' },
  { id: '2', name: 'Bob', email: '[email protected]' },
]

function App() {
  return (
    <ThemeProvider theme="light">
      <Grid columns={columns} data={data} style={{ width: 480, height: 300 }} />
    </ThemeProvider>
  )
}

Tree

import { Tree } from 'react-tree-grid/tree'
import { ThemeProvider } from 'react-tree-grid'
import type { TreeNode } from 'react-tree-grid/tree'

const data: TreeNode[] = [
  {
    id: 'root',
    value: 'Documents',
    $opened: true,
    items: [
      { id: 'file1', value: 'Report.pdf' },
      { id: 'file2', value: 'Notes.txt' },
    ],
  },
]

function App() {
  return (
    <ThemeProvider>
      <Tree data={data} checkbox onCheck={(ids) => console.log(ids)} />
    </ThemeProvider>
  )
}

TreeGrid

import { TreeGrid } from 'react-tree-grid/treegrid'
import { ThemeProvider } from 'react-tree-grid'
import type { TreeGridRow } from 'react-tree-grid/treegrid'

interface OrgRow extends TreeGridRow {
  name: string
  role: string
}

const columns = [
  { id: 'name', header: [{ text: 'Name' }], width: 200 },
  { id: 'role', header: [{ text: 'Role' }], width: 160 },
]

const data: OrgRow[] = [
  { id: 'ceo', name: 'Alice', role: 'CEO', $opened: true },
  { id: 'cto', name: 'Bob', role: 'CTO', parent: 'ceo' },
]

function App() {
  return (
    <ThemeProvider>
      <TreeGrid
        columns={columns}
        data={data}
        treeColumnId="name"
        style={{ width: 480, height: 300 }}
      />
    </ThemeProvider>
  )
}

Imports

The library supports both a single entry point and sub-path imports:

// All components from one import
import { Grid, Tree, TreeGrid, ThemeProvider } from 'react-tree-grid'

// Tree-shakeable sub-path imports
import { Grid } from 'react-tree-grid/grid'
import { Tree } from 'react-tree-grid/tree'
import { TreeGrid } from 'react-tree-grid/treegrid'

ThemeProvider

Wrap your app (or a subtree) with ThemeProvider to apply a theme:

import { ThemeProvider } from 'react-tree-grid'

<ThemeProvider theme="dark">
  {/* components here */}
</ThemeProvider>

ThemeProvider Props

| Prop | Type | Default | Description | |---|---|---|---| | theme | 'light' \| 'dark' | 'light' | Built-in theme to apply | | overrides | Partial<ThemeTokens> | — | Override individual design tokens | | children | ReactNode | — | Content to render inside the theme |

Theme overrides

Pass overrides to customise individual tokens:

<ThemeProvider
  theme="light"
  overrides={{ colorPrimary: '#e91e63', fontFamily: 'Inter, sans-serif' }}
>
  {/* ... */}
</ThemeProvider>

CSS custom properties

All theme values are exposed as CSS custom properties prefixed with --react-tree-grid-:

.my-element {
  color: var(--react-tree-grid-color-primary);
  font-size: var(--react-tree-grid-font-size-md);
  padding: var(--react-tree-grid-spacing-md);
}

Grid Props

| Prop | Type | Default | Description | |---|---|---|---| | columns | GridColumn[] | — | Column definitions | | data | GridRow[] | — | Row data | | rowHeight | number | — | Row height in pixels | | headerRowHeight | number | — | Header row height in pixels | | footerRowHeight | number | — | Footer row height in pixels | | sortable | boolean | false | Enable column sort | | selection | boolean \| 'row' \| 'cell' \| 'complex' | — | Selection mode | | multiselection | boolean | false | Allow multi-select | | editable | boolean | false | Enable inline editing | | keyNavigation | boolean | false | Keyboard navigation | | tooltip | boolean | false | Enable cell tooltips | | leftSplit | number | — | Freeze N left columns | | rightSplit | number | — | Freeze N right columns | | topSplit | number | — | Freeze N top rows | | bottomSplit | number | — | Freeze N bottom rows | | dragItem | 'item' \| 'both' | — | Enable row drag-and-drop | | adjust | boolean \| 'data' \| 'header' \| 'footer' | — | Auto-fit column widths | | autoHeight | boolean | false | Grow grid height to fit all rows | | groupable | boolean | false | Enable drag-panel grouping UI | | group | { order: string[] } | — | Initial grouping column order | | style | CSSProperties | — | Width/height (required for virtual scroll) | | className | string | — | Root element class name |

Grid Callbacks

Callbacks whose name starts with onBefore can return false to cancel the action.

| Callback | Signature | Description | |---|---|---| | onScroll | (state: { x: number; y: number }) => void | Fires on scroll | | onBeforeSort | (states: SortState[]) => boolean \| void | Return false to cancel sort | | onAfterSort | (states: SortState[]) => void | Fires after sort is applied | | onBeforeSelect | (rowId: string, colId: string) => boolean \| void | Return false to cancel selection | | onAfterSelect | (rowId: string, colId: string) => void | Fires after a cell is selected | | onBeforeUnSelect | (rowId: string, colId: string) => boolean \| void | Return false to cancel deselection | | onAfterUnSelect | (rowId: string, colId: string) => void | Fires after a cell is deselected | | onCellClick | (rowId: string, colId: string, event: MouseEvent) => void | Fires on cell click | | onCellDblClick | (rowId: string, colId: string, event: MouseEvent) => void | Fires on cell double-click | | onBeforeEditStart | (rowId: string, colId: string) => boolean \| void | Return false to prevent editing | | onAfterEditStart | (rowId: string, colId: string) => void | Fires when an editor opens | | onBeforeEditEnd | (rowId: string, colId: string, newValue: unknown, oldValue: unknown) => boolean \| void | Return false to discard the new value | | onAfterEditEnd | (rowId: string, colId: string, newValue: unknown) => void | Fires after a value is saved | | onBeforeRowDrop | (data: GridRowDragData, event: PointerEvent) => boolean \| void | Return false to cancel drop | | onAfterRowDrop | (data: GridRowDragData, event: PointerEvent) => void | Fires after a row is reordered | | onBeforeColumnDrop | (data: GridColumnDragData, event: DragEvent) => boolean \| void | Return false to cancel column reorder | | onAfterColumnDrop | (data: GridColumnDragData, event: DragEvent) => void | Fires after a column is reordered | | onResize | (colId: string, width: number) => void | Fires while a column is being resized | | onAfterResizeEnd | (colId: string, width: number) => void | Fires after column resize ends | | onBeforeGroupChange | (order: string[]) => boolean \| void | Return false to cancel grouping change | | onGroupChange | (order: string[]) => void | Fires after grouping order changes |

GridColumn

| Prop | Type | Description | |---|---|---| | id | string | Unique column identifier | | header | GridHeaderCell[] | Header cell configuration (supports multi-row headers) | | footer | GridFooterCell[] | Footer cell configuration | | width | number | Column width in pixels | | minWidth | number | Minimum width when resizing | | maxWidth | number | Maximum width when resizing | | hidden | boolean | Hide the column | | sortable | boolean | Override grid-level sortable for this column | | resizable | boolean | Allow the user to resize this column | | type | 'string' \| 'number' \| 'date' \| 'boolean' \| 'checkbox' | Column data type | | editorType | 'input' \| 'select' \| 'combo' \| 'checkbox' \| 'datePicker' \| 'multiselect' | Editor shown when the cell is in edit mode | | align | 'left' \| 'center' \| 'right' | Cell content alignment | | template | (value, row, column) => ReactNode | Custom cell renderer | | tooltipTemplate | (value, row, column) => string | Custom tooltip content | | tooltip | boolean | Enable tooltip for this column | | groupable | boolean | Allow this column to be used in the grouping panel | | mark | GridMarkConfig | Conditional cell styling rules | | adjust | 'header' \| 'data' \| 'all' | Auto-fit width for this column | | autoWidth | boolean | Stretch column to fill remaining space |

GridHeaderCell

interface GridHeaderCell {
  text?: string
  colspan?: number
  rowspan?: number
  content?: 'inputFilter' | 'selectFilter' | 'comboFilter'
  css?: string
}

GridFooterCell

interface GridFooterCell {
  text?: string
  colspan?: number
  content?: 'sum' | 'avg' | 'count' | 'min' | 'max'
  css?: string
}

Tree Props

| Prop | Type | Default | Description | |---|---|---|---| | data | TreeNode[] | — | Tree data | | checkbox | boolean | false | Show checkboxes | | editable | boolean | false | Enable inline label editing | | dragItem | 'item' \| 'both' | — | Drag-and-drop mode | | expanded | string[] | — | Controlled expanded node IDs | | defaultExpanded | string[] | — | Initially expanded node IDs (uncontrolled) | | selected | string[] | — | Controlled selected node IDs | | checked | string[] | — | Controlled checked node IDs |

Tree Callbacks

| Callback | Signature | Description | |---|---|---| | onSelect | (id: string) => void | Fires when a node is selected | | onCheck | (ids: string[]) => void | Fires when checkbox state changes; receives all checked IDs | | onExpand | (id: string) => void | Fires when a node is expanded | | onCollapse | (id: string) => void | Fires when a node is collapsed | | onEdit | (id: string, newValue: string) => void | Fires after an inline label edit | | onDrop | (dragId: string, targetId: string, position: 'before' \| 'after' \| 'inside') => void | Fires after a drag-and-drop reorder |

TreeGrid Props

Extends all Grid Props and adds:

| Prop | Type | Default | Description | |---|---|---|---| | data | TreeGridRow[] | — | Hierarchical row data | | treeColumnId | string | — | Column that renders the expand/collapse toggle | | collapsed | boolean | false | Start all nodes collapsed | | groupBy | string \| string[] | — | Group rows by one or more fields | | groupAggregate | GroupAggregateConfig | — | Aggregate values on group header rows | | dropBehaviour | 'child' \| 'sibling' \| 'complex' | 'complex' | How a dropped row is placed in the tree | | dragExpand | boolean | false | Auto-expand a node when a row is dragged over it |

TreeGrid Callbacks

TreeGrid inherits all Grid Callbacks. Row drop events carry additional context describing the tree position (parent, index) of the dropped row.

Types

GridRow

interface GridRow {
  id: string
  hidden?: boolean    // Hide the row without removing it from data
  $height?: number    // Per-row height override in pixels
  $css?: string       // Row-level CSS class name
  [key: string]: unknown
}

TreeGridRow

interface TreeGridRow extends GridRow {
  parent?: string        // ID of the parent row (flat data format)
  items?: TreeGridRow[]  // Inline nested children (nested data format)
  $opened?: boolean      // Start the node expanded
}

TreeNode

interface TreeNode {
  id: string
  value: string
  icon?: ReactNode
  items?: TreeNode[]
  disabled?: boolean
  $opened?: boolean  // Start the node expanded
}

GroupAggregateConfig

type GroupAggregateConfig = Record<string, 'sum' | 'avg' | 'count' | 'min' | 'max'>
// Sum the 'salary' column, count rows in 'department'
<TreeGrid
  groupBy="department"
  groupAggregate={{ salary: 'sum', department: 'count' }}
  ...
/>

SortState

interface SortState {
  columnId: string
  order: 'asc' | 'desc'
}

License

MIT