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

smartgrid-react-ui

v0.1.3

Published

React data grid with filtering, sorting, pagination, theming, and card view

Readme

smartgrid-react-ui

smartgrid-react-ui is a React data-grid library with:

  • useGrid (headless hook)
  • Grid (ready-to-use UI component)

This README is aligned with the DemoPage flow and shows exactly what to change per feature.


Install

npm i smartgrid-react-ui

Demo Flow (same as DemoPage)

  1. Final Product Grid (all features together)
  2. Basic Grid
  3. Enable Sorting
  4. Enable Filters (enum + date)
  5. Enable Selection + Delete Selected
  6. Date Filters operators/presets
  7. Formatted Cells
  8. Custom Row Action Buttons

In each snippet below, changed lines are marked with // CHANGED.


Shared Types and Base Columns

import { Grid, useGrid, type ColumnDef, type RowRecord } from "smartgrid-react-ui";

interface LeadRow extends RowRecord {
  id: number;
  name: string;
  company: string;
  email: string;
  phone: string;
  status: string;
  value: number;
  city: string;
  createdAt: string;
}

const leadColumns: ColumnDef<LeadRow>[] = [
  { field: "id", headerName: "ID", type: "number", sortable: true, filterable: true, width: 70 },
  { field: "name", headerName: "Name", type: "string", sortable: true, filterable: true },
  { field: "company", headerName: "Company", type: "string", sortable: true, filterable: true },
  { field: "email", headerName: "Email", type: "string", sortable: true, filterable: true },
  { field: "phone", headerName: "Phone", type: "string", sortable: true, filterable: true, searchable: false },
  {
    field: "status",
    headerName: "Status",
    type: "string",
    sortable: true,
    filterable: true,
    searchable: false,
    enumValues: ["New", "Contacted", "Qualified", "Won", "Lost"], // CHANGED: enum dropdown values
  },
  { field: "value", headerName: "Value", type: "number", sortable: true, filterable: true },
  { field: "city", headerName: "City", type: "string", sortable: true, filterable: true, searchable: false },
  {
    field: "createdAt",
    headerName: "Created At",
    type: "date", // CHANGED: date type enables date filter operators
    sortable: true,
    filterable: true,
    searchable: false,
  },
];

1) Basic Grid

const grid = useGrid<LeadRow>({
  columns: leadColumns,
  data: rows,
  enableSelection: false, // CHANGED: base demo state
  showSelectionCheckboxes: false, // CHANGED: base demo state
  enableSorting: false, // CHANGED: base demo state
  enableFilters: false, // CHANGED: base demo state
  paginationMode: "server",
  totalRowCount: total,
  getRowId: (row) => String(row.id),
});

<Grid grid={grid} className="h-full" showActionColumn={false} />;

2) Enable Sorting

const sortableColumns: ColumnDef<LeadRow>[] = [
  { field: "id", headerName: "ID", type: "number", sortable: true }, // CHANGED
  { field: "name", headerName: "Name", type: "string", sortable: true }, // CHANGED
  { field: "value", headerName: "Value", type: "number", sortable: true }, // CHANGED
  { field: "createdAt", headerName: "Created At", type: "date", sortable: true }, // CHANGED
];

const grid = useGrid<LeadRow>({
  columns: sortableColumns,
  data: rows,
  enableSelection: false,
  showSelectionCheckboxes: false,
  enableSorting: true, // CHANGED: sorting ON
  enableFilters: false,
  paginationMode: "server",
  totalRowCount: total,
});

3) Enable Filters (enum + date)

const filterableColumns: ColumnDef<LeadRow>[] = [
  { field: "name", headerName: "Name", type: "string", filterable: true }, // CHANGED
  {
    field: "status",
    headerName: "Status",
    type: "string",
    filterable: true, // CHANGED
    searchable: false, // CHANGED
    enumValues: ["New", "Contacted", "Qualified", "Won", "Lost"], // CHANGED
  },
  { field: "createdAt", headerName: "Created At", type: "date", filterable: true }, // CHANGED
];

const grid = useGrid<LeadRow>({
  columns: filterableColumns,
  data: rows,
  enableSelection: false,
  showSelectionCheckboxes: false,
  enableSorting: true,
  enableFilters: true, // CHANGED: filters ON
  paginationMode: "server",
  totalRowCount: total,
});

4) Enable Selection + Delete Selected (custom behavior)

const grid = useGrid<LeadRow>({
  columns: leadColumns,
  data: rows,
  enableSelection: true, // CHANGED
  showSelectionCheckboxes: true, // CHANGED
  enableSorting: true,
  enableFilters: true,
  paginationMode: "server",
  totalRowCount: total,
  getRowId: (row) => String(row.id),
});

<Grid
  grid={grid}
  onDeleteSelectedRows={(selectedRows) => { // CHANGED: your custom delete logic
    const ids = new Set(selectedRows.map((r) => r.id));
    setRows((prev) => prev.filter((r) => !ids.has(r.id))); // frontend delete example
    setTotal((prev) => Math.max(0, prev - ids.size));
  }}
/>;

If you want API delete instead:

onDeleteSelectedRows={async (selectedRows) => {
  await fetch("/api/leads/bulk-delete", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ ids: selectedRows.map((r) => r.id) }),
  });
  await refetchLeads();
}}

5) Date Filters (before / after / between / preset)

const dateColumns: ColumnDef<LeadRow>[] = [
  {
    field: "createdAt",
    headerName: "Created At",
    type: "date", // CHANGED
    sortable: true,
    filterable: true, // CHANGED
    searchable: false,
  },
];

const grid = useGrid<LeadRow>({
  columns: dateColumns,
  data: rows,
  enableFilters: true, // CHANGED
});

Available date filter operations:

  • before
  • after
  • between
  • preset: last7Days, last30Days, thisWeek, lastWeek, thisMonth, lastMonth

6) Formatted Cell (status badges)

const formattedColumns: ColumnDef<LeadRow>[] = leadColumns.map((col) =>
  col.field === "status"
    ? {
        ...col,
        renderCell: ({ value }) => { // CHANGED
          const status = String(value ?? "");
          // CHANGED: map value -> badge colors
          return <StatusBadge status={status} />;
        },
      }
    : col
);

7) Custom Row Actions (View / Edit / Delete)

const actionColumns: ColumnDef<LeadRow>[] = [
  ...leadColumns,
  {
    field: "actions", // CHANGED: added action column
    headerName: "Actions",
    type: "string",
    sortable: false, // CHANGED
    filterable: false, // CHANGED
    searchable: false, // CHANGED
    renderCell: ({ row }) => ( // CHANGED: your own action handlers
      <div style={{ display: "flex", gap: 6 }}>
        <button onClick={() => handleView(row)}>View</button>
        <button onClick={() => handleEdit(row)}>Edit</button>
        <button onClick={() => handleDelete(row)}>Delete</button>
      </div>
    ),
  },
];

Final Product Grid (all features together)

const grid = useGrid<LeadRow>({
  columns: finalColumns, // CHANGED
  data: rows,
  enableSelection: true, // CHANGED
  showSelectionCheckboxes: true, // CHANGED
  enableSorting: true, // CHANGED
  enableFilters: true, // CHANGED
  paginationMode: "server", // CHANGED
  totalRowCount: total, // CHANGED
  getRowId: (row) => String(row.id),
});

Server Pagination Pattern (Leads API)

useEffect(() => {
  async function load() {
    const sort = grid.sortModel[0];
    const payload = await fetchLeads({
      page: grid.pagination.pageIndex + 1, // CHANGED: map 0-based UI -> 1-based API
      limit: grid.pagination.pageSize, // CHANGED
      sortBy: sort?.field,
      order: sort?.direction ?? "asc",
    });
    setRows(payload.data ?? []);
    setTotal(payload.total ?? 0);
  }
  load();
}, [grid.pagination.pageIndex, grid.pagination.pageSize, grid.sortModel]);

Important Props (quick reference)

  • enableSelection
  • showSelectionCheckboxes
  • enableSorting
  • enableFilters
  • paginationMode (client | server)
  • totalRowCount (required for server mode)
  • onDeleteSelectedRows (custom bulk delete)

Development

npm install
npm run dev
npm run build