A React data table with sorting, row selection and a sticky header - for admin panels and record lists.
Table playground
Install Table
1. New project? One command installs the package and wires everything - see Installation:
pnpm dlx zyncat-ui init2. Import the component - it loads its own stylesheet:
import { Table } from '@zyncat/ui/table';Usage
import { Table } from '@zyncat/ui/table'; <Table rows={rows} columns={columns} rowKey="id" selectable />Compose Table in your application. No Tailwind or external styling library is required; every value resolves from Zyncat UI's token vocabulary.
Table props
Table
TableColumn
TableSort
Frequently asked questions
Set sortable: true on a column - clicking its header (or activateOn="click" instead of the pointerdown default) cycles asc to desc, sorting a copy of rows locally with a numeric-aware compare. Pass defaultSort={{ key, dir }} to start pre-sorted, or read onSortChange to sync the active sort elsewhere; rows re-flow with a FLIP animation, not a jump cut.
Set selectable - it adds a checkbox column plus a bulk-action bar that slides in from the header once anything is checked. Selection is a Set reported through onSelectionChange, shift-click extends the range across rows, and bulkActions(keys, clear) renders your own buttons next to the built-in Clear.
Two mechanisms, no viewport media queries: hideBelow="sm" or "md" drops a column once the table's own container - not the window - crosses a 30rem or 42rem @container breakpoint, and whatever's left scrolls horizontally with a pinned identity column (pinFirst, on by default) and a fading edge that signals there's more to scroll.
No - nothing here is virtualized or cell-editable; it's a presentational table for columns, rows and a render function, not a spreadsheet engine. AG Grid and MUI X's Data Grid solve windowing and inline editing at enterprise scale; this solves "declare columns and rows, get sorting, selection, a sticky header and overflow handling for free."
Pass columns and rows: each column is a key (also the default row[key] accessor), an optional label, and an optional render(row) for a custom cell - <Table columns={columns} rows={rows} rowKey="id" />. mono gives a column tabular numerals for IDs and timestamps, strong adds identity emphasis, and align or grow control text alignment and which column absorbs the slack width.
Yes to both. It ships with 'use client' intact for the Next.js App Router, renders a real table/thead/tbody with scope="col" headers and aria-sort on the active sort column, and has zero runtime dependencies. A loading table fades its rows to 45% opacity and sets aria-busy; the row-reorder animation collapses to 1ms under prefers-reduced-motion.