Data Table
Soft variant
Switch tabs, pick a role or plan, search, sort, select rows and page through 40 people. Suspend and delete work on a row or on the selection.
- Set
variant"soft" - once on
DataTable; every part — search, filters, page size, pagination, checkboxes, the batch bar — reads it from context. DataTableTabs- and
DataTableFilterfilter one field each (by), so the data keeps its own shape. Tab counts follow the search and the other filters. sticky- on a head and its cells pins the actions column to the right edge; it casts a shadow while more table hides under it.
Searchable DataTable
- Pass
data - and getRowId — everything else is composition. No column config.
sortBy- takes a dot path or an accessor function, so nested and computed values sort correctly.
Installation
New project? Follow the installation guide to set up Tailwind CSS, shadcn, the cn helper and lucide-react, register the @algorize-ui registry once, then copy your styles from the Themes page.
Install Table
components/ is written into your project. Copy any snippet from a Usage tab above and it runs.
Install dependencies
Step 1 installs this for you. Run it yourself only if you are adding Table to an existing project by hand. The cn helper and lucide-react are not listed — the installation guide covers them once for every component.
toggle-group is a component, not a package — the shadcn CLI installs it as source files.
Soft variant
variant="soft" is the admin-dashboard look: a rounded panel on a hairline ring, a tinted header band, pill controls and calm round row actions, every tint mixed from the table colour. Everything below lives inside the panel — status tabs with live counts, select filters, search, a reset, the page's actions, sortable columns with a pinned actions column, a rows-per-page picker, pagination and a floating bar for the selected rows. The first example on this page is a soft table — its Usage tab is the preview's exact source.The parts that come with it
DataTableTabs, DataTableFilter and DataTableReset filter and clear; TableAction is the toolbar button (primary, secondary, ghost); TableRowAction is a round icon button that needs a label; TableBadge is a status pill (tone) or, without its dot, a tag; TablePerson draws an avatar with a name and a second line; DataTableBatchAction goes inside the batch bar. They work in every variant and take the soft look inside a soft table.
Empty results explain themselves
Give DataTableEmpty an icon, title, description and action, and read search, isFiltered and resetAll from useDataTable (in table-core) to say whether nothing matched or nothing exists yet — the example's NoUsers does exactly that.
Features
No data transformation
getRowId resolves id, _id or uuid out of the box, dot paths reach into nested objects, and accessor functions cover anything computed.
Opt-in controls
Search, page size, pagination and selection are separate components. Leave one out and the feature is simply not there — no boolean flags to manage.
Typed sorting
Numbers compare numerically by default rather than lexically, and sortType lets you force string, number or date comparison.
Escape hatch
useDataTable exposes the whole state — rows, search, sort, paging, selection — so you can build your own toolbar or pager on the same provider.
Best Practices & Guidelines
Give rows a stable id
Selection is tracked by id, not by index, so it survives sorting and paging. If your rows have no natural key, derive one before passing the array in — an array index will unselect the wrong row as soon as the order changes.
Client-side by design
Search, sort and paging all run over the array you pass in. For server-driven datasets, use the plain Table primitives and drive the query yourself — or keep DataTable for the current page only and supply your own footer.
Give a function sortBy an id
A string sortBy doubles as its own identity. When you pass an accessor function, add sortId so the active-sort indicator stays stable across re-renders.
Props Reference
| Component | Prop | Type | Default | Description |
|---|---|---|---|---|
DataTable | data | T[] | Required | Your rows, in whatever shape they arrive. |
DataTable | getRowId | (row: T) => string | number | id → _id → uuid | How a row is identified for selection and expansion. |
DataTable | getSearchText | (row: T) => string | all values | Override what the search box matches against. |
DataTable | initialSort | { id, direction?, type? } | undefined | Sort applied on first render. |
DataTable | pageSize | number | 2nd option | Starting page size. |
DataTable | pageSizeOptions | number[] | [5, 10, 25, 50] | Choices offered by DataTablePageSize. |
DataTable | onSelectionChange | (rows: T[]) => void | — | Fires when the selection changes, with the full row objects. |
DataTable | variant | "default" | "minimal" | "glass" | "soft" | "default" | Visual skin of the container, rows and every control. soft is the admin-dashboard look shown above. |
DataTable | color | "primary" | "indigo" | "rose" | "emerald" | "zinc" | string | "primary" | Accent theme color for active selection, soft borders, hover highlights, and active elements. Accepts preset names or custom hex codes. |
DataTable | size | "sm" | "md" | "lg" | "md" | Density padding and text sizing for table cells and toolbars. |
DataTableHead | sortBy | string | ((row: T) => unknown) | — | A dot path such as "profile.name", or an accessor function. Its presence makes the header sortable. |
DataTableHead | sortId | string | the path | Required only when sortBy is a function. |
DataTableHead | sortType | "auto" | "string" | "number" | "date" | "auto" | auto compares numbers numerically and everything else as text. |
DataTableHead | align | "left" | "center" | "right" | "left" | Text alignment. |
DataTableBatchBar | children | ((args: { selectedRows: T[]; selectedIds: (string | number)[]; clearSelection: () => void }) => ReactNode) | ReactNode | — | Render function or nodes for the floating batch actions bar. |
DataTableBatchBar | floating | boolean | true | Floats over the bottom center of the table when true; set false for inline rendering. |
DataTableSearch | placeholder | string | "Search…" | Placeholder text for the search input box. |
DataTableSelectAll | className | string | — | Header checkbox to select or deselect all rows on the current page. |
DataTableSelect | className | string | — | Row checkbox to select or deselect the specific row. |
DataTableSelect | label | string | "Select row" | Accessible name of the row checkbox, e.g. Select Priya Nair. |
DataTableHead, DataTableCell | sticky | boolean | false | Pins the column to the right edge. Set it on the head and on every cell of the column. |
DataTableTabs | by | string | ((row: T) => unknown) | Required | The field the tabs filter on — a dot path or an accessor function (add filterId for functions). |
DataTableTabs | tabs | { value: string; label: ReactNode }[] | Required | One tab per value. The tab whose value is allValue shows every row. |
DataTableTabs | allValue | string | "all" | The value of the show-everything tab. |
DataTableTabs | showCounts | boolean | true | Each tab shows how many rows it would leave, counting the search and the other filters. |
DataTableFilter | by | string | ((row: T) => unknown) | Required | The field to match exactly (an array field matches any of its entries). Add filterId for functions. |
DataTableFilter | options | (string | { label: string; value: string })[] | Required | The choices. Use objects when the stored value differs from the label. |
DataTableFilter | placeholder | string | Required | Shown while nothing is chosen, e.g. Role. Also names the filter for screen readers unless you pass label. |
DataTableFilter | side | "top" | "bottom" | "bottom" | Which way the menu opens. |
DataTableReset | variant | "primary" | "secondary" | "ghost" | "ghost" | Clears the search, every filter and the sort. Renders only while there is something to clear; takes every TableAction prop. |
DataTablePageSize | side | "top" | "bottom" | "top" in soft | Which way the menu opens. The soft picker sits in the footer, so it opens upward. |
DataTableBatchBar | noun | [string, string] | — | Singular and plural for the count: ["user", "users"] reads “3 users selected”. |
DataTableBatchAction | tone | "default" | "danger" | "default" | A button for the batch bar; danger for destructive actions. |
DataTableEmpty | icon, title, description, action | ReactNode | — | A full empty state: an icon chip, what is missing, what to do, and a button. Without them it is the one-line message it always was. |
TableAction | variant | "primary" | "secondary" | "ghost" | "secondary" | A toolbar button in the table's look. Icons passed as children are sized for you. |
TableAction | size | "sm" | "md" | "md" | Button height and text size. |
TableRowAction | label | string | Required | A round icon button for a row; label is its accessible name and hover title. Group them in TableRowActions (always visible in soft). |
TableRowAction | tone | "default" | "danger" | "default" | danger turns red on hover. |
TableBadge | tone | "neutral" | "success" | "warning" | "danger" | "info" | "neutral" | The status colour. The label always shows, so colour is never the only signal. |
TableBadge | dot | boolean | true | Turn it off for a plain tag. |
TablePerson | name | string | Required | The name; the initials take a colour kept per name when there is no photo. |
TablePerson | description | ReactNode | — | A muted second line, e.g. an email. |
TablePerson | src | string | — | A photo. If it fails to load, the initials show. |
TablePerson | imageComponent | ElementType | "img" | Renders the photo — pass next/image in a Next.js app. |