One headless engine.
Every UI kit.
Headless freedom, batteries included for your kit. The same table features render natively in Mantine, MUI, Chakra, Ant Design, Radix, Base UI, shadcn/Tailwind — or your own custom UI. URL state, RTL, and a real filter UX, out of the box.
One table. Eight UI kits.
The same dataset and feature set, re-rendered by each real adapter — Mantine, MUI, Chakra, Ant Design, Radix, Base UI, shadcn and Tailwind. Nothing about the table changes but its skin.
Everything a data table owes you.
Columns & filters
One declaration drives the widget, the URL params, the chips and the row predicate. Operator-first number and date filters: Equal, At least, At most, Between.
Three data tiers
Hand the table an array and it filters, sorts and pages in memory. Or own the fetch: one consolidated query event with an abort signal. Or bring a full custom TableSource.
URL-synced everything
Search, sort, filters, pagination, column layout and saved views live in shareable URLs — namespaced per table, SSR-safe, with a one-prop opt-out (urlSync={false}).
50,000 rows, no flinching
Opt-in virtualization windows the DOM against the page or any max-height scroll box. The live demo scrolls fifty thousand rows with a handful of DOM nodes.
i18n & RTL, for real
Label presets for 18 locales. Columns map per-locale data paths, so cells, sorting and filtering follow the language. Pinning and layout are logical — Arabic and Hebrew just work.
Column management
Show, hide, reorder, pin and resize — the row-actions column included. Capture any state as a named saved view and restore it later, per table.
Selection & bulk actions
Select the page — or all matches across every page. Bulk actions run through an injectable confirm, and per-row actions explain themselves with disabledReason.
Accessible by default
Real table roles, aria-sort, focus management and full keyboard navigation — column reorder and resize included, straight from the keyboard.
Shape, edit, carry and export the data.
Grouping & pivots
Drag headers into a grouping panel and pick Sum, Average, Min, Max or Count per column — or pivot dimensions across both axes with collapsible subtotals.
Inline editing
Text, number, select and date editors with validation, batch save and undo. Every write is a callback, so your application owns the data.
Mobile cards
Below 768px the rows become cards with the same search, filters, selection and URL state — no second layout to build.
CSV, Excel & PDF export
Export the exact view on screen — the page, every matching row, the selection or a cell range — in the browser or through your server.
Ask the table in plain words.
An opt-in assistant drives the same governed actions a reader has — filter, group, aggregate, hide and reorder columns. Writes wait for approval by default, and @adapttable/aiships no model SDK: you connect the model you run.
Easy when you want. Headless when you need.
Start with props and grow all the way to prop-getters — at no point do you hit a wall and have to eject.
Props
Pass data, columns and a row key. Sensible defaults do the rest.
<DataTable data={rows} columns={cols}
rowKey={(r) => r.id} />Slots
Swap the empty, no-results, error and skeleton states.
slots={{ empty: <NoResults/>,
skeleton: <Shimmer/> }}classNames + data-*
Style the kit's parts; target rows by state.
classNames={{ table: 'rounded-xl' }}
// [data-selected] [data-pinned]Custom toolbar
Add your own toolbar controls and confirm dialog.
toolbarSlots={{ start: <Title/> }}
confirm={myConfirm}Fully headless
Prop-getters. You own every element.
const { getRowProps,
getHeaderCellProps } = useDataTable(opts)A few lines to your first table.
The CLI detects your UI kit and scaffolds a working table; the docs cover every prop, the three data tiers, theming, i18n/RTL and the TanStack comparison.
import { DataTable } from "@adapttable/mantine"; // or mui, chakra, antd, radix, base-ui, shadcn, unstyled
import { filters } from "@adapttable/mantine/filters";
<DataTable
data={people}
rowKey={(person) => person.id}
columns={[
{ key: "name" },
{ key: "team", filter: "multiSelect" },
{ key: "hiredAt", filter: "dateRange" },
]}
features={[filters([])]}
/>npx @adapttable/cli init