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

react-light-table

v3.1.2

Published

A lightweight React data table with sorting, pagination, filtering, selection, virtualization, and theming

Readme

React Light Table

A lightweight, customizable React data table with sorting, pagination, filtering, selection, virtualization, and accessible defaults. No heavy dependencies — just React.

Features

  • Sorting — single or multi-column (Shift+click)
  • Pagination — client-side or manual/server mode
  • Filtering — global search and per-column filters
  • Selection — single/multiple rows with bulk action bar
  • Expandable rows and tree/hierarchical data
  • Column controls — visibility toggle, resize, drag reorder
  • Virtual scrolling for large datasets
  • Inline cell editing
  • CSV export (all rows or selected only)
  • Theming — light/dark, compact density, striped/bordered variants
  • Customization — design tokens, class name slots, custom renderers
  • Headless hookuseReactLightTable for custom UIs
  • Accessibilityaria-sort, keyboard sort, pagination labels
  • React 18 and 19 support

Installation

npm install react-light-table

Import the stylesheet once in your app:

import "react-light-table/style.css";

Quick start

import { ReactLightTable } from "react-light-table";
import "react-light-table/style.css";

const columns = [
  { key: "name", title: "Name", sortable: true },
  { key: "age", title: "Age", sortable: true },
];

const data = [
  { name: "John Doe", age: 30 },
  { name: "Jane Doe", age: 25 },
];

export function MyTable() {
  return (
    <ReactLightTable
      columns={columns}
      data={data}
      sortable
      showFilter
      hasPagination
      rowsPerPage={10}
    />
  );
}

Sorting

Single-column sort cycles asc → desc → none on header click.

<ReactLightTable columns={columns} data={data} sortable />

Multi-column sort — hold Shift while clicking headers:

<ReactLightTable columns={columns} data={data} sortable multiSort />

Controlled sort state accepts a single sort or an array:

import { ReactLightTable, type SortState } from "react-light-table";

const [sort, setSort] = useState<SortState>({ key: "name", mode: "asc" });

<ReactLightTable
  columns={columns}
  data={data}
  sortable
  multiSort
  sort={sort}
  onSortChange={setSort}
/>

Filtering

Global search

<ReactLightTable
  columns={columns}
  data={data}
  showFilter
  filterPlaceholder="Search..."
/>

Per-column filters

Define filter on columns ("text" or "select") and enable the filter row:

const columns = [
  { key: "name", title: "Name", filter: "text" },
  {
    key: "department",
    title: "Department",
    filter: "select",
    filterOptions: [
      { label: "Engineering", value: "Engineering" },
      { label: "Design", value: "Design" },
    ],
  },
];

<ReactLightTable
  columns={columns}
  data={data}
  showColumnFilters
  columnFilters={columnFilters}
  onColumnFiltersChange={setColumnFilters}
/>

For server-driven filtering, use controlled filterValue / onFilterChange with manualFiltering, or manualColumnFiltering for column filters.

Row selection & bulk actions

<ReactLightTable
  columns={columns}
  data={data}
  selectable="multiple"
  rowKey={(row) => row.id}
  selectedRowKeys={selected}
  onSelectionChange={(keys, rows) => setSelected(keys)}
  bulkActionsContent={
    <button type="button" onClick={handleDelete}>Delete selected</button>
  }
  showExport
  exportSelected
/>

Server-side / manual mode

<ReactLightTable
  columns={columns}
  data={currentPageRows}
  sortable
  hasPagination
  rowsPerPage={20}
  sort={sort}
  onSortChange={setSort}
  page={page}
  onPageChange={setPage}
  filterValue={query}
  onFilterChange={setQuery}
  showFilter
  manualSorting
  manualPagination
  manualFiltering
  totalRows={totalCount}
  loading={isLoading}
/>

Virtual scrolling

For large lists, enable virtualization. Row entrance animations are automatically disabled in virtual mode.

<ReactLightTable
  columns={columns}
  data={largeDataset}
  virtualized
  scroll={{ y: 400 }}
  virtualRowHeight={44}
/>

Tree data

<ReactLightTable
  columns={columns}
  data={treeData}
  treeData
  childrenColumn="children"
  rowKey={(row) => row.id}
  expandedRowKeys={expanded}
  onExpandedChange={setExpanded}
/>

Expandable rows

<ReactLightTable
  columns={columns}
  data={data}
  expandable
  rowKey={(row) => row.id}
  expandedRowKeys={expanded}
  onExpandedChange={setExpanded}
  renderExpandedRow={(row) => <div>{row.details}</div>}
/>

Inline editing

Enable editing per column and handle changes:

const columns = [
  { key: "name", title: "Name", editable: true },
  { key: "age", title: "Age", editable: true, editType: "number" },
  {
    key: "status",
    title: "Status",
    editable: true,
    editType: "select",
    editOptions: [
      { label: "Active", value: "active" },
      { label: "Inactive", value: "inactive" },
    ],
  },
];

<ReactLightTable
  columns={columns}
  data={data}
  rowKey={(row) => row.id}
  onCellChange={(row, key, value) => updateRow(row, key, value)}
/>

Column resize, reorder & sticky columns

<ReactLightTable
  columns={columns}
  data={data}
  resizable
  reorderable
  columnWidths={widths}
  onColumnWidthsChange={setWidths}
  columnOrder={order}
  onColumnOrderChange={setOrder}
  scroll={{ x: 800 }}
  stickyColumn="first"
/>

Table variants

<ReactLightTable columns={columns} data={data} variant="striped" />
<ReactLightTable columns={columns} data={data} variant="bordered" />

CSV export

Built-in toolbar button:

<ReactLightTable columns={columns} data={data} showExport exportFilename="export.csv" />

Or use the utility directly:

import { exportToCsv } from "react-light-table";

exportToCsv({ data, columns, filename: "export.csv", columnVisibility });

Customization

Design tokens (appearance)

<ReactLightTable
  columns={columns}
  data={data}
  appearance={{
    accent: "#8b5cf6",
    background: "#ffffff",
    foreground: "#1e293b",
    border: "#e2e8f0",
    radius: "1rem",
    shadow: "0 8px 24px rgba(15, 23, 42, 0.08)",
  }}
/>

Class name slots (classNames)

<ReactLightTable
  columns={columns}
  data={data}
  classNames={{
    root: "my-table",
    toolbar: "my-table-toolbar",
    surface: "my-table-surface",
    scrollContainer: "my-table-scroll",
    table: "my-table-el",
    row: "my-table-row",
    cell: "my-table-cell",
    pagination: "my-table-pagination",
    bulkActions: "my-table-bulk",
  }}
/>

Set disableAnimations to opt out of motion. Override CSS variables on the root — see defaultTableAppearance for the full token list.

Theme & density

<ReactLightTable columns={columns} data={data} theme="dark" size="compact" />

Headless API

Use useReactLightTable to drive your own UI while reusing all table state logic:

import { useReactLightTable } from "react-light-table";

function CustomTable(props) {
  const table = useReactLightTable(props);
  const { visibleRows, requestSort, setFilterValue } = table;
  // render your own markup
}

Exported utilities

| Export | Description | |--------|-------------| | ReactLightTable | Main table component | | useReactLightTable | Headless state/handler hook | | exportToCsv | Client-side CSV download | | processTableData | Filter → sort → paginate pipeline | | flattenTreeRows | Flatten hierarchical data | | toggleSort / getPrimarySort / normalizeSortState | Sort state helpers | | applyAppearance / defaultTableAppearance | Theme token helpers |

Development

npm install
npm run build
npm test
npm run typecheck
npm run lint
npm run dev:playground   # http://localhost:5173

The playground includes scenarios for pagination, filtering, selection, server mode, virtualization, tree data, editing, bulk actions, and more.

Upgrading to v3

  • onSortChange now receives SortState (SortProps | SortProps[] | null) instead of only a single SortProps. Use getPrimarySort(sort) if you only need the first active sort.
  • Import the stylesheet: import "react-light-table/style.css".
  • Virtual mode automatically disables row entrance animations — no action needed.

See CHANGELOG.md for the full release history.

Documentation

License

MIT