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

@pyreon/table

v0.36.0

Published

Pyreon adapter for TanStack Table

Readme

@pyreon/table

Pyreon adapter for TanStack Table — reactive useTable + flexRender.

@pyreon/table wraps @tanstack/table-core so a Pyreon app gets all the headless table machinery (sorting, filtering, pagination, grouping, expanding, faceting) with signal-driven options. useTable(() => opts) returns a Computed<Table<TData>> whose backing instance is mutated in place — a version counter forces the computed to re-notify on state changes. flexRender handles the four column-def shapes TanStack supports (string, number, function, VNode). The full @tanstack/table-core surface is re-exported, so consumers import everything from @pyreon/table.

Install

bun add @pyreon/table @pyreon/core @pyreon/reactivity
# @tanstack/table-core is a hard dependency, installed automatically

Quick start

import { signal } from '@pyreon/reactivity'
import {
  useTable,
  flexRender,
  createColumnHelper,
  getCoreRowModel,
  getSortedRowModel,
} from '@pyreon/table'

type Person = { name: string; age: number }

const columnHelper = createColumnHelper<Person>()
const columns = [
  columnHelper.accessor('name', { header: 'Name' }),
  columnHelper.accessor('age', { header: 'Age' }),
]

function UserTable() {
  const data = signal<Person[]>([
    { name: 'Alice', age: 30 },
    { name: 'Bob', age: 25 },
  ])

  const table = useTable(() => ({
    data: data(),
    columns,
    getCoreRowModel: getCoreRowModel(),
    getSortedRowModel: getSortedRowModel(),
  }))

  return () => (
    <table>
      <thead>
        {table()
          .getHeaderGroups()
          .map((hg) => (
            <tr>
              {hg.headers.map((header) => (
                <th>{flexRender(header.column.columnDef.header, header.getContext())}</th>
              ))}
            </tr>
          ))}
      </thead>
      <tbody>
        {table()
          .getRowModel()
          .rows.map((row) => (
            <tr>
              {row.getVisibleCells().map((cell) => (
                <td>{flexRender(cell.column.columnDef.cell, cell.getContext())}</td>
              ))}
            </tr>
          ))}
      </tbody>
    </table>
  )
}

useTable(() => options)

Create a reactive table instance. Options are a function — read signals (data, columns, sorting state) inside and the table updates automatically.

| Parameter | Type | Description | | --------- | ----------------------------- | --------------------------------------------- | | options | () => TableOptions<TData> | Function returning TanStack TableOptions |

Returns Computed<Table<TData>>call it to get the instance: table().getRowModel().

The adapter creates the table instance once (via createTable) and mutates it in place on option changes. State sync is wired via the adapter's own onStateChange (composed with the user's, if any). A version counter is bumped on every state / option change so the computed re-emits even though the table reference is stable.

Controlled state

import { signal } from '@pyreon/reactivity'
import type { SortingState, PaginationState } from '@pyreon/table'

const sorting = signal<SortingState>([])
const pagination = signal<PaginationState>({ pageIndex: 0, pageSize: 10 })

const table = useTable(() => ({
  data: data(),
  columns,
  state: {
    sorting: sorting(),
    pagination: pagination(),
  },
  onSortingChange: (u) => sorting.set(typeof u === 'function' ? u(sorting.peek()) : u),
  onPaginationChange: (u) =>
    pagination.set(typeof u === 'function' ? u(pagination.peek()) : u),
  getCoreRowModel: getCoreRowModel(),
  getSortedRowModel: getSortedRowModel(),
  getPaginationRowModel: getPaginationRowModel(),
}))

flexRender(component, props)

Render any TanStack column-def template (header, cell, footer). Handles strings, numbers, functions, and VNodes; returns null for anything else (including null/undefined).

// Header cell:
flexRender(header.column.columnDef.header, header.getContext())

// Data cell:
flexRender(cell.column.columnDef.cell, cell.getContext())

// Footer cell:
flexRender(footer.column.columnDef.footer, footer.getContext())

Custom cell renderers can be functions that return JSX:

columnHelper.accessor('name', {
  header: 'Name',
  cell: (info) => <strong>{info.getValue()}</strong>,
})

Re-exports from @tanstack/table-core

Everything from @tanstack/table-core is re-exported — createColumnHelper, getCoreRowModel, getSortedRowModel, getFilteredRowModel, getPaginationRowModel, getGroupedRowModel, getExpandedRowModel, getFacetedRowModel, getFacetedMinMaxValues, getFacetedUniqueValues, plus types Table, ColumnDef, SortingState, PaginationState, RowData, RowSelectionState, ColumnFiltersState, GroupingState, ExpandedState, etc.

A drift snapshot test in src/tests/public-surface.test.ts locks the re-export set — when TanStack adds, renames, or removes an export in a minor bump, the snapshot fails and the diff becomes the deliberate decision moment (run bunx vitest run --update public-surface to accept).

Gotchas

  • useTable returns Computed<Table<TData>> — call it (table()) to access the table. Reading without calling captures the computed reference, not the instance.
  • Options must be a function () => opts, not a plain object. Signals read inside the function auto-track and the table reconfigures on change.
  • Same instance, version counter — the table reference is stable across updates; the adapter bumps a version signal so the computed re-emits. Don't compare table references for change detection.
  • onStateChange composition — the adapter wires its own handler that updates internal state, then calls your onStateChange after. If you override at the option-level it still runs; if you wire per-field (onSortingChange, etc.), only those fire.
  • Sync effect disposes on unmount via onUnmount. The table instance itself has no dispose — its lifecycle is the component's.

Documentation

Full docs: pyreon.dev/docs/table (or docs/src/content/docs/table.md in this repo).

License

MIT