A theme-aware data grid: sort, filter, search, select, edit, expand, paginate, pin, resize and more.
Table is the workhorse for rows of comparable records: scan, sort, filter, search, select, edit in place and drill into a row. Every feature is opt-in, so the same component covers a three-column read-only list and a full editable grid. It reads its colours from tokens, so it follows the theme on the page. For a vertical stack of single ideas reach for a List; for quick filters use Pills.
| Bank name | Sector | Doc. category | Doc Size | ||
|---|---|---|---|---|---|
| ClearView Compliance | Valley National | Finance | Certificate | ₹7,62,432 | 12.3 MB |
| EverGreen Audit Partners | Sunrise | Transportation | Financial Statements | ₹7,38,762 | 40 MB |
| BlueSky Financial Reviews | SilverWave | Healthcare | Policies | ₹1,23,240 | 192 KB |
| Integrity Audit Solutions | RiverStone Com | Pharmaceuticals | Training Manuals | ₹43,600 | 120 KB |
| GoldLeaf Risk Advisors | Pinnacle Trust B. | Hospitality | Tax Filings | ₹45,680 | 8 MB |
| SummitPoint Assurance | Maple Ridge | Agriculture | Project Plans | ₹49,150 | 540 KB |
{ columns, data }: sort a header, and that is it. Everything else is opt-in.| Bank name | Sector | Doc. category | ||
|---|---|---|---|---|
| ClearView Compliance | Valley National | Finance | Certificate | ₹7,62,432 |
| EverGreen Audit Partners | Sunrise | Transportation | Financial Statements | ₹7,38,762 |
| BlueSky Financial Reviews | SilverWave | Healthcare | Policies | ₹1,23,240 |
| Integrity Audit Solutions | RiverStone Com | Pharmaceuticals | Training Manuals | ₹43,600 |
| GoldLeaf Risk Advisors | Pinnacle Trust B. | Hospitality | Tax Filings | ₹45,680 |
| SummitPoint Assurance | Maple Ridge | Agriculture | Project Plans | ₹49,150 |
| TrueNorth Audit | Horizon Bank | Finance | HR Records | ₹10,520 |
| Meridian Controls | Valley National | Transportation | Certificate | ₹5,22,090 |
| Bank name | Sector | Doc. category | ||
|---|---|---|---|---|
| ClearView Compliance | Valley National | Finance | Certificate | ₹7,62,432 |
| EverGreen Audit Partners | Sunrise | Transportation | Financial Statements | ₹7,38,762 |
| BlueSky Financial Reviews | SilverWave | Healthcare | Policies | ₹1,23,240 |
| Integrity Audit Solutions | RiverStone Com | Pharmaceuticals | Training Manuals | ₹43,600 |
| GoldLeaf Risk Advisors | Pinnacle Trust B. | Hospitality | Tax Filings | ₹45,680 |
| SummitPoint Assurance | Maple Ridge | Agriculture | Project Plans | ₹49,150 |
| TrueNorth Audit | Horizon Bank | Finance | HR Records | ₹10,520 |
| Meridian Controls | Valley National | Transportation | Certificate | ₹5,22,090 |
| Auditor | Filing | Totals | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| Bank name | Sector | Doc. category | Firm Reg. number | Doc Size | ||||||
| ClearView Compliance | Valley National | Finance | Certificate | REG-10234 | 29 Jun 2022 | ₹7,62,432 | 12.3 MB | |||
| EverGreen Audit Partners | Sunrise | Transportation | Financial Statements | REG-10607 | 15 Mar 2024 | ₹7,38,762 | 40 MB | |||
| BlueSky Financial Reviews | SilverWave | Healthcare | Policies | REG-10980 | 19 Oct 2022 | ₹1,23,240 | 192 KB | |||
| Integrity Audit Solutions | RiverStone Com | Pharmaceuticals | Training Manuals | REG-11353 | 03 Mar 2020 | ₹43,600 | 120 KB | |||
| GoldLeaf Risk Advisors | Pinnacle Trust B. | Hospitality | Tax Filings | REG-11726 | 22 Aug 2023 | ₹45,680 | 8 MB | |||
| SummitPoint Assurance | Maple Ridge | Agriculture | Project Plans | REG-12099 | 11 Jan 2023 | ₹49,150 | 540 KB | |||
| TrueNorth Audit | Horizon Bank | Finance | HR Records | REG-12472 | 07 Sep 2021 | ₹10,520 | 2.1 MB | |||
| Meridian Controls | Valley National | Transportation | Certificate | REG-12845 | 18 Feb 2024 | ₹5,22,090 | 76 KB | |||
| Anchor Assurance | Sunrise | Healthcare | Policies | REG-13218 | 29 Jun 2022 | ₹2,20,960 | 290 KB | |||
| Northgate Audit Co | SilverWave | Pharmaceuticals | Legal Documents | REG-13591 | 15 Mar 2024 | ₹8,92,330 | 12 MB | |||
A cell renders whatever you return from column.render. Switch to the Cells tab to see rows built from our own components: an Avatar and Avatar group, a status Badge, an Indicator dot, Tags, a star rating, a Progress bar, a sparkline, a Toggle, a Link, and a Button plus an icon Button.
| Owner | Status | Progress | Plan | |
|---|---|---|---|---|
| GreenLeaf Financial | Ivy Lane | Active | 82% | Enterprise |
| Pro Property | Ravi Kumar | Pending | 47% | Growth |
| Nova Retail | Mia Ono | Active | 66% | Growth |
| Alro Kroperty | Sam Lee | Paused | 23% | Starter |
| Feature | Behaviour |
|---|---|
| Sort | Sortable columns become header buttons. Click cycles ascending, descending, then off; numeric columns sort numerically. |
| Filter | A funnel on filterable columns opens a menu of the distinct values. Tick any to narrow the rows; Clear resets. |
| Search | A single toolbar box filters across every column at once. |
| Select | A leading checkbox column with a header select-all and an indeterminate state for a partial selection. |
| Edit | Click a row to edit every editable cell at once, inline; a bar offers Save or Discard, and validation blocks a bad save. |
| Column menu | A kebab on each header opens sort, pin (left/right/none), autosize, autosize-all, group by, choose columns and reset. |
| Groups | Columns that share a group render a spanning second-level header above them. |
| Query | The advanced filter builds column / operator / value conditions (equals, does not equal, contains, greater than …) matched all or any. |
| Validate | A column validator flags a bad cell with a red border and X, tints the row, and counts into the toolbar chip. |
| Expand | renderDetail adds a disclosure column; expanding a row reveals a panel below it, often a nested table. |
| Paginate | pageSize splits the rows and shows a compact pager with the total count. |
| Pin | Freeze a column to the left or right, and pin summary rows to the top or bottom, so key data stays in view while the rest scrolls. |
| Resize | Drag a header's right edge to widen or narrow a column; the frozen columns and their offsets keep up. |
| Refine | Row numbers, floating per-column filters, a column-hover tint, a status bar and right-to-left layout, each an independent flag. |
Two orthogonal knobs shape the grid without touching its features. Flip them live with the controls above the demo.
| Prop | Options | What changes |
|---|---|---|
| density | compact · default · comfortable | Tightens or opens up the row height for dense tables or airy ones. Header and body move together. |
| appearance | line · grid · zebra | line keeps only row hairlines, grid draws every cell border for spreadsheet-style data, zebra stripes alternate rows and drops the hairline. |
| borderless | boolean | Removes the outer border and radius so the grid sits flush inside a surface you already frame, like a card or a panel. |
<Table columns={columns} data={rows} density="compact" appearance="grid" />
<Table columns={columns} data={rows} appearance="zebra" />
<Table columns={columns} data={rows} borderless />| Prop | Type | Notes |
|---|---|---|
| columns | Column<T>[] | Per column: key, header, align, width, sortable, filterable, value, render, editable, editor, options, validate |
| data | T[] | The rows, each keyed by the column keys |
| title / actions | ReactNode | Toolbar left title and right-side slot for buttons |
| searchable | boolean | Adds the global search box to the toolbar |
| selectable | boolean | Adds the checkbox column and header select-all |
| selected / onSelectedChange | string[] · (ids) => void | Controlled selection; omit both for uncontrolled |
| editable | boolean | Master switch; columns opt in with editable + editor. Editing a cell opens the whole row inline with Save / Discard |
| onCellEdit | (rowId, key, value) => void | Fires per cell when a row's edits are saved |
| renderDetail | (row) => ReactNode | Enables expandable master/detail rows |
| pageSize | number | Rows per page. Omit to render every row |
| pageSizeOptions | number[] | Rows-per-page choices shown as a footer selector, e.g. [5, 10, 20] |
| advancedFilter | boolean | Toolbar query builder: [column] [operator] value, matched all or any |
| columns[].group | string | Adjacent columns sharing it get a spanning group header |
| columns[].pinned | left | right | Freeze that column against an edge on horizontal scroll |
| pinnedRows | { top?: T[]; bottom?: T[] } | Rows frozen top / bottom, outside sort, filter and paging |
| resizable | boolean | Drag a header's right edge to resize the column |
| rowNumbers | boolean | A leading 1-based index column |
| floatingFilters | boolean | A per-column filter row: text columns get a checkbox value list, number columns add a range slider |
| columns[].type | text | number | Drives the floating filter's control; auto-inferred from the data if omitted |
| columnHover | boolean | Tint the whole column under the cursor |
| statusBar | boolean | A footer strip with the row and selection counts |
| rtl | boolean | Lay the grid out right-to-left |
| density | compact | default | comfortable | Row height |
| appearance | line | grid | zebra | Row separators: hairlines, full cell borders, or stripes |
| borderless | boolean | Drop the outer frame for full-bleed embedding |
| getRowId / stickyHeader | (row, i) => string · boolean | Stable ids; pin the header while the body scrolls |
Nothing in the grid is a hard-coded colour. It reads these token roles, so switching data-theme on the page recolours the whole grid, dark to daylight, with no prop changes. Try the toggle in the demo above.
| Token role | Where it lands |
|---|---|
| --surface / --surface-raised | Grid field and the header / hover fill |
| --border / --border-subtle | Outer border and the hairline between rows |
| --accent / --on-accent | Active sort, current page, selection tint |
| --danger-solid / --danger-surface | Cell error border, X icon and the row tint |
| --warning-surface / --warning-text | The toolbar error chip |
| --font-mono | Header labels and numeric cells |
| --radius-12 / --shadow-2 | Panel radius and the filter / editor menus |
import { Table, type Column } from "./ui/components/table/table";
type Row = { id: string; name: string; sector: string; category: string; seats: number };
const columns: Column<Row>[] = [
{ key: "name", header: "Name", sortable: true },
{ key: "sector", header: "Sector", filterable: true },
{
key: "category", header: "Category",
editable: true, editor: "select", options: CATEGORIES,
validate: (v) => (v === "Policies" ? "Not an allowed category" : null),
},
{ key: "seats", header: "Seats", align: "right", sortable: true },
];
<Table
columns={columns}
data={rows}
getRowId={(r) => r.id}
title="Data subjects"
searchable
selectable
editable
onCellEdit={(id, key, value) => save(id, key, value)}
renderDetail={(r) => <ChargesTable owner={r.id} />}
pageSize={10}
/>