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

@forgedevstack/grid-table

v1.0.9

Published

A powerful, headless grid table component for React with SCSS styling, drag-and-drop columns, filtering, sorting, and responsive mobile support

Downloads

230

Readme

@forgedevstack/grid-table

@forgedevstack/grid-table v1.0.8 — A powerful, feature-rich data grid for React with 30+ features including cell editing, multi-format export, keyboard navigation, context menu, tree data, row reordering, frozen rows, undo/redo, print mode, and server-driven (manual) pagination. Zero-config SCSS styling. Part of ForgeStack.

Features

Core

  • Server-driven paginationpaginationConfig.manualPagination + totalRowCount: pass one page in data and load more in onPageChange (see portal Server-driven demo).
  • Cell Editing — Double-click to edit inline with validation (text, number, select, date, boolean)
  • Dark/Light Theme — Built-in theme support with customizable colors
  • Filtering — Column-level and global filtering with multiple operators
  • Sorting — Single and multi-column sorting with custom sort functions
  • Drag & Drop — Reorder columns by dragging
  • Column Resize — Adjust column widths by dragging
  • Pagination — Built-in pagination with customizable page sizes
  • Row Selection — Single and multi-select support
  • Row Expansion — Expandable rows with custom content
  • Responsive — Default horizontal scroll table on small screens; optional mobileLayout="stacked" for card layout. Drawer for filters/sorting. Disable breakpoints with mobileBreakpoint="none".

v1.0.8

  • Mobile layoutmobileLayout="scroll" (default) shows the full header and columns with swipe scrolling; mobileLayout="stacked" uses the stacked card layout.
  • Hover — Softer row hover when tableEffects.hover is enabled.

v1.0.7

  • Keyboard Navigation — Arrow keys, Tab, Enter to edit, Escape, Home/End, PageUp/Down
  • Context Menu — Right-click for copy, filter, pin, hide. Custom actions supported
  • Tree Data — Hierarchical rows with expand/collapse, indentation, and toggle arrows
  • Status Bar — Footer with row count, selected count, and column aggregations (sum, avg, min, max)
  • Row Reordering — Drag-and-drop rows with visual handle
  • Excel Export — SpreadsheetML XML export, no dependencies
  • PDF Export — Print-dialog-based PDF with styled table
  • CSV / JSON Export — One-click export with enableExport
  • Copy to Clipboard — Tab-separated clipboard copy
  • Undo/Redo — Edit history with Ctrl+Z / Ctrl+Y (Cmd on Mac)
  • Column Pinning — Runtime pin/unpin columns left or right
  • Column Auto-Fit — Double-click to auto-size, or global auto-fit
  • Frozen Rows — Pin rows to top or bottom of viewport
  • Print Mode — Styled printable view with title and date

Display

  • Table Effects — Sort animations, row entry effects, hover highlights
  • Lazy Load — Infinite scroll with configurable batch size
  • Skeleton Loading — Beautiful loading states
  • Overflow Tooltip — Show full cell content on hover when truncated
  • Expandable Sub-cell — Extra content per cell via double-click or arrow
  • Studio Panel — Development/prototyping side panel
  • Context API — No prop drilling, access state from anywhere
  • TypeScript — Full type safety
  • Accessible — ARIA attributes and keyboard navigation

Installation

npm i @forgedevstack/grid-table

Import CSS (Required)

import '@forgedevstack/grid-table/grid-table.css';

Bear styles are loaded automatically.

Quick Start

import { GridTable } from '@forgedevstack/grid-table';
import type { ColumnDefinition } from '@forgedevstack/grid-table';

interface User {
  id: number;
  name: string;
  email: string;
  role: string;
  [key: string]: unknown;
}

const columns: ColumnDefinition<User>[] = [
  { id: 'name', accessor: 'name', header: 'Name', sortable: true, filterable: true },
  { id: 'email', accessor: 'email', header: 'Email', sortable: true },
  { id: 'role', accessor: 'role', header: 'Role', filterType: 'select', filterOptions: [{ value: 'admin', label: 'Admin' }, { value: 'user', label: 'User' }] },
];

const data: User[] = [
  { id: 1, name: 'John Doe', email: '[email protected]', role: 'admin' },
  { id: 2, name: 'Jane Smith', email: '[email protected]', role: 'user' },
];

function App() {
  return (
    <GridTable
      data={data}
      columns={columns}
      enableRowSelection
      showPagination
      showFilter
      enableExport
      tableEffects={{ hover: true, sort: true, row: true }}
    />
  );
}

Cell Editing

Double-click any editable cell to edit inline. Press Enter to save, Escape to cancel.

const columns: ColumnDefinition<User>[] = [
  {
    id: 'name',
    accessor: 'name',
    header: 'Name',
    editable: true,
  },
  {
    id: 'role',
    accessor: 'role',
    header: 'Role',
    editable: {
      enabled: true,
      type: 'select',
      options: [
        { value: 'admin', label: 'Admin' },
        { value: 'editor', label: 'Editor' },
        { value: 'viewer', label: 'Viewer' },
      ],
      validate: (value) => value ? true : 'Role is required',
      onSave: (row, columnId, oldValue, newValue) => {
        console.log('Saved:', { row, columnId, oldValue, newValue });
      },
    },
  },
];

<GridTable
  data={data}
  columns={columns}
  enableCellEdit
  onCellEdit={(row, columnId, oldValue, newValue) => {
    console.log('Cell edited:', { row, columnId, oldValue, newValue });
  }}
/>

Export (CSV, JSON, Excel, PDF)

<GridTable
  data={data}
  columns={columns}
  enableExport={['csv', 'json', 'excel', 'pdf']}
  exportFileName="my-data"
  enableCopy
  printConfig={{ enabled: true, title: 'My Report' }}
/>

Or use the utilities directly:

import { exportToCSV, exportToJSON, exportToExcel, exportToPDF, copyToClipboard, printTable } from '@forgedevstack/grid-table';

exportToCSV(data, columns, 'my-report');
exportToJSON(data, columns, 'my-report');
exportToExcel(data, columns, 'my-report');
exportToPDF(data, columns, 'my-report', 'Report Title');
copyToClipboard(data, columns);
printTable(data, columns, 'Print Title');

Table Effects

Unified tableEffects prop controls all animations:

<GridTable
  data={data}
  columns={columns}
  tableEffects={{
    hover: true,
    sort: true,
    row: true,
  }}
/>

Each effect accepts true for defaults or a config object:

tableEffects={{
  hover: { enabled: true, bgColor: '#1a1a2e', accentBorder: true, className: 'my-hover' },
  sort: { enabled: true, flash: true, bounce: true },
  row: { enabled: true, staggerMs: 50, className: 'my-row-enter' },
  className: 'effects-active',
}}

Tree Data

Render hierarchical data with expand/collapse:

const treeData = [
  { id: 1, name: 'CEO', children: [
    { id: 2, name: 'CTO', children: [
      { id: 3, name: 'Lead Dev' },
    ]},
    { id: 4, name: 'CFO' },
  ]},
];

<GridTable
  data={treeData}
  columns={columns}
  treeData={{ enabled: true, childrenField: 'children', expandAll: false }}
/>

Row Expansion

<GridTable
  data={employees}
  columns={columns}
  enableRowExpansion
  defaultExpandedIds={[1, 5]}
  renderRowExpansion={(row) => <EmployeeDetail employee={row} />}
/>

Keyboard Navigation

<GridTable
  data={data}
  columns={columns}
  keyboardNavigation={{ enabled: true, enableEditOnEnter: true, wrap: true }}
/>

Arrow keys move between cells. Enter starts editing. Tab moves to next cell. Escape cancels editing.

Context Menu

<GridTable
  data={data}
  columns={columns}
  contextMenu={{
    enabled: true,
    showCopy: true,
    showFilter: true,
    showPin: true,
    showHide: true,
    actions: [
      { id: 'custom', label: 'Custom Action', onClick: (ctx) => console.log(ctx.value) },
    ],
  }}
/>

Status Bar

<GridTable
  data={data}
  columns={columns}
  statusBar={{
    enabled: true,
    showRowCount: true,
    showSelectedCount: true,
    showFilteredCount: true,
    aggregations: [
      { columnId: 'salary', type: 'sum', label: 'Total Salary', format: (v) => `$${v.toLocaleString()}` },
      { columnId: 'age', type: 'avg', label: 'Avg Age' },
    ],
  }}
/>

Row Reordering

<GridTable
  data={data}
  columns={columns}
  rowReorder={{ enabled: true }}
  onRowReorder={(newOrder) => setData(newOrder)}
/>

Undo/Redo

<GridTable
  data={data}
  columns={columns}
  enableCellEdit
  undoRedo={{ enabled: true, maxHistory: 50 }}
  onUndo={(rowId, colId, value) => console.log('Undone:', rowId, colId, value)}
  onRedo={(rowId, colId, value) => console.log('Redone:', rowId, colId, value)}
/>

Frozen Rows

<GridTable
  data={data}
  columns={columns}
  frozenRows={{
    top: [summaryRow],
    bottom: [totalRow],
  }}
/>

Print Mode

<GridTable
  data={data}
  columns={columns}
  printConfig={{
    enabled: true,
    title: 'Sales Report',
    showDate: true,
  }}
/>

Lazy Load / Infinite Scroll

<GridTable
  data={data}
  columns={columns}
  lazyLoad={{
    enabled: true,
    initialRows: 10,
    batchSize: 10,
    showLoader: true,
  }}
/>

Theming

const customTheme: Partial<Theme> = {
  mode: 'dark',
  colors: {
    background: { primary: '#1a1a2e', secondary: '#16213e', tertiary: '#0f3460', hover: '#1a1a2e' },
    text: { primary: '#eaeaea', secondary: '#a0a0a0', muted: '#707070' },
    accent: { primary: '#22c55e', success: '#4ade80', warning: '#fbbf24', error: '#f87171' },
  },
};

<GridTable data={data} columns={columns} theme={customTheme} />

Bear Integration

Grid-table uses @forgedevstack/bear for UI controls. Set themeMode and themeOverride on GridTable to control Bear components inside:

<GridTable
  data={data}
  columns={columns}
  themeMode="dark"
  themeOverride={{
    colors: {
      primary: '#22c55e',
      background: { default: '#0a0a14', paper: '#1a1a2e' },
      text: { primary: '#f8fafc', secondary: '#94a3b8' },
    },
  }}
/>

Translations

const customTranslations: Partial<Translations> = {
  empty: 'No records found',
  loading: 'Fetching data...',
  search: 'Search users...',
  rowsPerPage: 'Show',
};

<GridTable data={data} columns={columns} translations={customTranslations} />

Responsive Breakpoints

<GridTable
  data={data}
  columns={columns}
  mobileBreakpoint="tablet"
  mobileLayout="scroll"
  showMobileLabels={true}
  dimensions={{
    width: { mobile: '100%', tablet: '100%', desktop: 800 },
    height: { mobile: 400, tablet: 500, desktop: 600 },
  }}
/>

Use mobileLayout="stacked" for the previous label-per-cell mobile layout.

Using Hooks

import { TableProvider, useTable } from '@forgedevstack/grid-table';

function TableControls() {
  const { filter, sort, selection } = useTable();
  return (
    <div>
      <button onClick={() => filter.clearFilters()}>Clear Filters</button>
      <button onClick={() => sort.clearSorting()}>Clear Sort</button>
      <span>{selection.selectedIds.size} rows selected</span>
    </div>
  );
}

Studio

Development panel for inspecting data, props, and generating sample rows:

<GridTable data={data} columns={columns} studio />

API Reference

GridTable Props

| Prop | Type | Default | Description | |------|------|---------|-------------| | data | T[] | Required | Array of data objects | | columns | ColumnDefinition<T>[] | Required | Column definitions | | loading | boolean | false | Show loading skeleton | | error | Error \| string | null | Error to display | | theme | Partial<Theme> | Dark theme | Custom theme colors | | translations | Partial<Translations> | English | Custom text labels | | themeMode | 'light' \| 'dark' \| 'system' | — | Light/dark mode | | themeOverride | Record<string, unknown> | — | Bear theme object | | enableDragDrop | boolean | true | Column reordering | | enableColumnResize | boolean | true | Column resizing | | enableRowSelection | boolean | false | Row selection | | enableMultiSelect | boolean | false | Multi-row selection | | enableRowExpansion | boolean | false | Row expansion | | enableCellEdit | boolean | false | Enable inline cell editing | | enableExport | boolean \| string \| string[] | false | Export buttons: true, 'csv', ['csv','excel','pdf'] | | exportFileName | string | 'grid-table-export' | Export file name | | enableCopy | boolean | false | Show copy-to-clipboard button | | contextMenu | ContextMenuConfig | — | Right-click context menu | | statusBar | StatusBarConfig | — | Footer status bar | | frozenRows | FrozenRowsConfig | — | Pin rows to top/bottom | | treeData | TreeConfig | — | Hierarchical tree data | | keyboardNavigation | KeyboardNavConfig | — | Arrow key navigation | | rowReorder | RowReorderConfig | — | Drag-and-drop row reorder | | onRowReorder | (rows) => void | — | Row reorder callback | | undoRedo | UndoRedoConfig | — | Edit undo/redo | | onUndo | (rowId, colId, value) => void | — | Undo callback | | onRedo | (rowId, colId, value) => void | — | Redo callback | | printConfig | PrintConfig | — | Print mode config | | autoFit | AutoFitConfig | — | Column auto-fit | | showPagination | boolean | true | Pagination controls | | showFilter | boolean | true | Filter controls | | showGlobalFilter | boolean | true | Global search | | showOverflowTooltip | boolean | true | Tooltip on truncated cells | | stickyHeader | boolean | true | Sticky header | | tableEffects | TableEffects | — | Sort/hover/row animations | | defaultExpandedIds | Array<string \| number> | — | IDs to expand on mount | | lazyLoad | LazyLoadConfig | — | Infinite scroll config | | onCellEdit | (row, colId, old, new) => void | — | Cell edit callback | | onRowClick | (row, index) => void | — | Row click callback | | onRowSelect | (selectedRows) => void | — | Selection callback | | onSort | (sorting) => void | — | Sort change callback | | onPageChange | (page, pageSize) => void | — | Page change callback | | studio | boolean | false | Show Studio panel |

ColumnDefinition

| Property | Type | Description | |----------|------|-------------| | id | string | Unique column identifier | | accessor | string \| (row) => unknown | Data accessor | | header | ReactNode \| () => ReactNode | Header content | | width | ResponsiveValue<number \| string> | Column width | | align | 'left' \| 'center' \| 'right' | Text alignment | | sortable | boolean | Enable sorting | | filterable | boolean | Enable filtering | | draggable | boolean | Allow drag reorder | | resizable | boolean | Allow resize | | hidden | boolean | Initially hidden | | editable | boolean \| CellEditConfig | Enable inline editing | | render | (value, row, index) => ReactNode | Custom cell renderer | | filterType | 'text' \| 'number' \| 'select' \| ... | Filter input type | | showOverflowTooltip | boolean | Tooltip on truncated cell | | renderSubCell | (row) => ReactNode | Expandable sub-content |

TableEffects

| Property | Type | Description | |----------|------|-------------| | hover | boolean \| HoverEffectConfig | Hover highlight effect | | sort | boolean \| SortEffectConfig | Sort animation effect | | row | boolean \| RowEffectConfig | Row entry animation | | className | string | Custom class on root |

LazyLoadConfig

| Property | Type | Default | Description | |----------|------|---------|-------------| | enabled | boolean | Required | Enable lazy loading | | initialRows | number | 20 | Rows shown initially | | batchSize | number | 10 | Rows per scroll load | | showLoader | boolean | true | Show loading indicator | | loadingContent | ReactNode | — | Custom loader |

CellEditConfig

| Property | Type | Description | |----------|------|-------------| | enabled | boolean | Enable editing for this column | | type | 'text' \| 'number' \| 'select' \| 'date' \| 'boolean' | Input type | | options | Array<{ value, label }> | Options for select type | | validate | (value, row) => string \| true | Validation function | | onSave | (row, colId, old, new) => void | Save callback | | placeholder | string | Input placeholder |

Exports

import {
  // Components
  GridTable,
  EditableCell,
  GridHeader,
  GridBody,
  GridRow,
  GridCell,
  Pagination,
  Skeleton,
  EmptyState,
  ContextMenu,
  StatusBar,
  // Context
  TableProvider,
  useTableContext,
  // Hooks
  useTable,
  useSort,
  useFilter,
  usePagination,
  useDragDrop,
  useBreakpoint,
  useKeyboardNavigation,
  useRowReorder,
  useUndoRedo,
  useTreeData,
  // Utils
  exportToCSV,
  exportToJSON,
  exportToExcel,
  exportToPDF,
  copyToClipboard,
  printTable,
  computeAggregation,
} from '@forgedevstack/grid-table';

Portal

The grid-table portal is a full documentation + demo website:

  • Home — Feature showcase, demo mesh, ecosystem banner
  • Demos — Finance (live data), HR (tree view), Basic (all props)
  • Playground — Toggle props live, auto-generated code
  • Theme Builder — Customize colors and export code
  • Docs — Getting started, API reference, guides
  • Changelog — Full version history
  • i18n — English and Spanish
  • Cmd+K — Quick search across all pages

Run the portal:

cd portal && npm i && npm run dev

License

MIT