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

arts-datatable

v0.1.0

Published

Reusable React data table with server-side query mode, backend-driven filters, exports, URL sync, fixed columns, and card view.

Readme

arts-datatable

Reusable data table for React projects with:

  • server-side pagination
  • server-side sorting
  • backend-driven filters
  • CSV export
  • PDF export
  • table / card view
  • URL sync
  • inline expandable rows
  • fixed columns
  • column resize
  • column reorder
  • table virtualization

Built with:

  • React
  • MUI
  • @tanstack/react-table

Install

npm install arts-datatable

Required peer dependencies:

npm install react react-dom @mui/material @mui/icons-material @mui/x-date-pickers @emotion/react @emotion/styled @tanstack/react-table dayjs

For PDF export the package already uses:

  • html2canvas
  • jspdf

They are loaded lazily only when user clicks PDF.

Exports

import { ArtsDataTable, buildArtsTableSearchParams } from 'arts-datatable';
import type {
  ArtsApiFilter,
  ArtsApiFilterOption,
  ArtsApiResponse,
  ArtsColumnDef,
  ArtsDataTableProps,
  ArtsRowAction,
  ArtsTableQuery,
  ArtsTableSort,
  ArtsToolbarAction
} from 'arts-datatable';

Basic usage

import { ArtsDataTable } from 'arts-datatable';

<ArtsDataTable
  title="My cases"
  columns={columns}
  request={requestCases}
/>

Request mode

import { buildArtsTableSearchParams, type ArtsApiResponse, type ArtsTableQuery } from 'arts-datatable';

const requestCases = async (query: ArtsTableQuery): Promise<ArtsApiResponse<CaseItem, CaseAccess>> => {
  const searchParams = buildArtsTableSearchParams(query);
  const response = await fetch(`/api/cases?${searchParams.toString()}`);

  if (!response.ok) {
    throw new Error(`Request failed with status ${response.status}`);
  }

  return response.json();
};

Response mode

<ArtsDataTable
  columns={columns}
  response={response}
  loading={loading}
  error={error}
/>

Backend response shape

type ArtsApiResponse<TData, TAccess = unknown> = {
  _payload: TData[];
  _meta?: {
    total?: number;
  };
  _access?: TAccess;
  _filters?: ArtsApiFilter[];
  code?: number;
  message?: string;
};

_filters is backend-driven. Supported filter types:

  • text
  • date
  • select
  • multi_select
  • date_range

Example:

[
  {
    "type": "text",
    "slug": "debtor",
    "label": "Պարտապան"
  },
  {
    "type": "multi_select",
    "slug": "status",
    "label": "Կարգավիճակ",
    "options": [
      { "value": "sent", "label": "Ուղարկված" },
      { "value": "bankrupted", "label": "Սնանկ ճանաչված" }
    ]
  },
  {
    "type": "date_range",
    "slug": "inscription_date",
    "label": "Մակագրման ամսաթիվ"
  }
]

Query shape

type ArtsTableQuery = {
  page: number;
  limit: number;
  sort?: {
    field: string;
    direction: 'asc' | 'desc';
  };
  filters: Record<
    string,
    string | number | boolean | null | undefined | string[] | { from?: string; to?: string }
  >;
};

Generated URL examples:

?page=1&limit=50
?page=1&limit=50&sort=-inscribed_status_created_at
?page=1&limit=50&filters[debtor]=...
?page=1&limit=50&filters[status][]=sent&filters[status][]=bankrupted
?page=1&limit=50&filters[inscription_date][from]=2026-05-01&filters[inscription_date][to]=2026-05-31

Columns

import type { ArtsColumnDef } from 'arts-datatable';

export const columns: ArtsColumnDef<RowItem>[] = [
  {
    key: 'code',
    header: 'Code',
    sort: true,
    fixed: true
  },
  {
    key: 'status',
    header: 'Status',
    sort: true,
    cell: info => <StatusChip value={info.row.original.status} />,
    exportValue: row => row.status
  }
];

Important column options:

  • key: field name from row object
  • header: visible header
  • cell: custom renderer
  • sort: enables server-side sorting
  • sortField: backend field name if different
  • fixed: true | 'left' | 'right'
  • display: false or 'exclude'
  • exportValue: value for CSV/PDF export

Use exportValue only for computed/custom cells:

{
  key: 'status',
  cell: info => <StatusChip value={info.row.original.status} />,
  exportValue: row => row.status
}

For simple fields like code or uuid, exportValue is not needed.

Core props

<ArtsDataTable
  title="My cases"
  columns={columns}
  request={requestCases}
  emptyText="Տվյալներ չկան"
  noDataText="Տվյալ չկա"
  errorText="Տվյալները բեռնել չհաջողվեց"
/>

Useful props:

  • enableCsvExport
  • csvFileName
  • enablePdfExport
  • pdfFileName
  • enableUrlSync
  • urlSyncKey
  • enableRowSelection
  • enableColumnVisibility
  • enableColumnResize
  • enableColumnReorder
  • enableVirtualization
  • virtualRowHeight
  • renderExpandedContent
  • rowActions
  • toolbarActions

CSV / PDF export

<ArtsDataTable
  columns={columns}
  request={requestCases}
  enableCsvExport
  csvFileName="court-cases"
  enablePdfExport
  pdfFileName="court-cases"
/>

Export uses:

  • currently loaded rows
  • currently visible columns
  • exportValue, if column provides it

Action column is excluded automatically.

URL sync

<ArtsDataTable
  columns={columns}
  request={requestCases}
  enableUrlSync
  urlSyncKey="court-cases"
/>

Synced values:

  • page
  • limit
  • sort
  • filters
  • view

Expandable rows

import type { Row } from '@tanstack/react-table';

const renderExpandedContent = (row: Row<CaseItem>) => (
  <div>{row.original.uuid}</div>
);

<ArtsDataTable
  columns={columns}
  request={requestCases}
  renderExpandedContent={renderExpandedContent}
/>

If renderExpandedContent is missing, expand UI is not shown.

Fixed columns

{
  key: 'code',
  fixed: true
}

{
  key: 'uuid',
  fixed: 'right'
}

__actions__ column is pinned to the right automatically.

Column resize

Resize works in table mode. By default it is enabled.

<ArtsDataTable
  columns={columns}
  request={requestCases}
  enableColumnResize
/>

User can:

  • drag header edge
  • double click resize handle to reset width

If you want to disable:

<ArtsDataTable enableColumnResize={false} />

Column reorder

Reorder is available from the columns menu.

<ArtsDataTable
  columns={columns}
  request={requestCases}
  enableColumnReorder
/>

User can move each column left or right from the columns menu.

If you want to disable:

<ArtsDataTable enableColumnReorder={false} />

Virtualization

Virtualization works in table mode and is useful for large pages.

<ArtsDataTable
  columns={columns}
  request={requestCases}
  enableVirtualization
  virtualRowHeight={56}
/>

Notes:

  • it virtualizes only table rows
  • it uses fixed row height
  • when expanded rows are opened, virtualization is disabled automatically for correct height rendering

Filters UI

Text filters are debounced by default:

<ArtsDataTable filterDebounceMs={400} />

You can also switch filter mode:

<ArtsDataTable filterMode="submit" />

select and multi_select are rendered with MUI Autocomplete.

Row actions

const getRowActions = row => [
  {
    label: 'View',
    onClick: row => console.log(row.original)
  }
];

<ArtsDataTable
  columns={columns}
  request={requestCases}
  rowActions={getRowActions}
/>

Toolbar actions

const getToolbarActions = access => [
  {
    label: 'Create',
    onClick: () => {}
  }
];

<ArtsDataTable
  columns={columns}
  request={requestCases}
  toolbarActions={getToolbarActions}
/>

Full example

import { ArtsDataTable } from 'arts-datatable';
import type { Row } from '@tanstack/react-table';

const renderExpandedContent = (row: Row<CaseItem>) => (
  <div>{row.original.uuid}</div>
);

<ArtsDataTable
  title="Իմ դատական գործերը"
  columns={columns}
  request={requestCases}
  enableCsvExport
  enablePdfExport
  enableUrlSync
  enableVirtualization
  renderExpandedContent={renderExpandedContent}
  rowActions={getRowActions}
  toolbarActions={getToolbarActions}
/>