Shadcn Data Table Components

Powerful table and datagrids built using TanStack Table. All table examples coexist cleanly with Radix UI and Base UI components. Browse our collection of 6 Shadcn Data Table variants.

Status
Amount
success
ken99@example.com
$316.00
success
Abe45@example.com
$242.00
processing
Monserrat44@example.com
$837.00
success
Silas22@example.com
$874.00
failed
carmella@example.com
$721.00
0 of 5 row(s) selected.

Table with expandable rows

StatusDate
Total
SO-1001
Ken Adams
ken99@example.com
processing
2024-01-15
$352.00
SO-1002
Abe Stone
abe45@example.com
fulfilled
2024-01-16
$279.00
SO-1003
Monserrat Lee
monserrat44@example.com
pending
2024-01-17
$904.00
SO-1004
Silas Chen
silas22@example.com
fulfilled
2024-01-18
$959.00
SO-1005
Carmella Diaz
carmella@example.com
cancelled
2024-01-19
$721.00
0 of 5 row(s) selected.

With vertical scroll

Status
Amount
success
ken99@example.com
$316.00
success
Abe45@example.com
$242.00
processing
Monserrat44@example.com
$837.00
success
Silas22@example.com
$874.00
failed
carmella@example.com
$721.00
success
john.doe@example.com
$523.00
processing
jane.smith@example.com
$689.00
pending
bob.wilson@example.com
$445.00
success
alice.brown@example.com
$912.00
failed
charlie.davis@example.com
$278.00
0 of 10 row(s) selected.

Draggable rows

Status
Amount
success
ken99@example.com
$316.00
success
Abe45@example.com
$242.00
processing
Monserrat44@example.com
$837.00
success
Silas22@example.com
$874.00
failed
carmella@example.com
$721.00
0 of 5 row(s) selected.

Draggable columns

Status
Email
Amount
Actions
success
ken99@example.com
$316.00
success
Abe45@example.com
$242.00
processing
Monserrat44@example.com
$837.00
success
Silas22@example.com
$874.00
failed
carmella@example.com
$721.00
0 of 5 row(s) selected.

With action buttons

Status
Amount
success
ken99@example.com
$316.00
success
Abe45@example.com
$242.00
processing
Monserrat44@example.com
$837.00
success
Silas22@example.com
$874.00
failed
carmella@example.com
$721.00
0 of 5 row(s) selected.
Unlock premium components
Get full control of shadcn/ui components, blocks and instances, including future additions.

Explore Shadcn Blocks

Ready-made page sections built with the same components.

View all blocks

Shadcn Data Table Component

The Shadcn Data Table turns a plain HTML table into an interactive grid with sorting, filtering, pagination, row selection and column visibility. It is the backbone of admin panels, order lists, user management screens and any page where people need to scan, search and act on many records at once.

Rows that expand into order details, columns you can reorder by dragging and a sticky header over a scrolling body go well beyond a basic grid. Each shadcn data table here takes its sorting, filtering and pagination logic from TanStack Table, a headless library, and renders it with shadcn/ui, React and Tailwind CSS, while the checkboxes and dropdown menus around it work with both Radix UI and Base UI.

What is the Shadcn Data Table Component?

shadcn/ui does not ship a single DataTable component. A data table is a pattern: you describe your columns with TanStack's ColumnDef, create a table instance with useReactTable, and render the resulting rows with the styled table parts from components/ui/table. Sorting, filtering and pagination are enabled by adding the matching row models, and the state lives in your component, so you decide whether it runs in the browser or on the server.

Use a data table when users need to find, compare or act on records. For a short, read-only list such as an invoice summary or a pricing comparison, the simpler Table is enough. If the records are visual and do not need columns, a list of Items or Cards is often easier to read on small screens.

Anatomy of the Shadcn Data Table

PartDescription
TableThe table element inside a horizontally scrollable container, so wide tables never break the page layout.
TableHeaderThe thead element that holds one TableRow per TanStack header group.
TableBodyThe tbody element for the rendered rows, including the empty state row when there are no results.
TableFooterAn optional tfoot element for totals or summaries.
TableRowA row with hover styling. Set data-state="selected" to highlight selected rows.
TableHeadA header cell. It usually holds the column title or a ghost button that toggles sorting.
TableCellA body cell that renders the column's cell function through flexRender.
TableCaptionAn optional caption that describes the table for screen reader users.
useReactTable and flexRenderExports from @tanstack/react-table that create the table instance and render header and cell definitions.

6 Shadcn Data Table Variants

Each data table variant listed here is previewed live at the top of this page, together with its source code and install command.

  • Full featured: A payments table with an email filter, a sortable email column, row selection with checkboxes, a column visibility menu, a bulk actions menu for selected rows and Previous and Next pagination. The other variants build on this same toolbar.
  • Expandable rows: An orders table where clicking a row or its chevron button reveals a detail panel with payment, shipping, line items and order totals.
  • Vertical scroll: Caps the table container at a fixed height and keeps the header row sticky while the rows scroll underneath it.
  • Draggable rows: Reorders rows with a grip handle button using dnd-kit, restricted to the vertical axis, with mouse, touch and keyboard sensors registered.
  • Draggable columns: Lets users rearrange the data columns by dragging a grip handle in each header, restricted to the horizontal axis. The selection and actions columns stay pinned at the edges, and the order is kept in React state and passed to the table as columnOrder.
  • Row action buttons: Inline edit and delete icon buttons plus a more menu at the end of every row.

How to Install the Shadcn Data Table Component

Set up shadcn/ui in your project if you have not already, then add the Shadcn UI Kit registry to your components.json once:

{
  "registries": {
    "@shadcnuikit": "https://shadcnuikit.com/r/{name}.json"
  }
}

Then install a data table variant by its name:

npx shadcn@latest add @shadcnuikit/data-table1

The same command works with pnpm dlx, yarn dlx and bunx --bun. Each variant has a copy button for every package manager, and the code is added to your project as plain React and Tailwind CSS that you can edit freely.

How to Use the Shadcn Data Table Component

Install @tanstack/react-table and the table component, define your columns, then render the header groups and rows with the table parts. Add row models such as getSortedRowModel for each feature you need.

"use client"

import * as React from "react"
import {
  type ColumnDef,
  type SortingState,
  flexRender,
  getCoreRowModel,
  getSortedRowModel,
  useReactTable,
} from "@tanstack/react-table"

import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from "@/components/ui/table"

type Payment = { id: string; email: string; amount: number }

const columns: ColumnDef<Payment>[] = [
  { accessorKey: "email", header: "Email" },
  { accessorKey: "amount", header: "Amount" },
]

export function PaymentsTable({ data }: { data: Payment[] }) {
  const [sorting, setSorting] = React.useState<SortingState>([])
  const table = useReactTable({
    data,
    columns,
    state: { sorting },
    onSortingChange: setSorting,
    getCoreRowModel: getCoreRowModel(),
    getSortedRowModel: getSortedRowModel(),
  })

  return (
    <Table>
      <TableHeader>
        {table.getHeaderGroups().map((group) => (
          <TableRow key={group.id}>
            {group.headers.map((header) => (
              <TableHead key={header.id}>
                {flexRender(header.column.columnDef.header, header.getContext())}
              </TableHead>
            ))}
          </TableRow>
        ))}
      </TableHeader>
      <TableBody>
        {table.getRowModel().rows.map((row) => (
          <TableRow key={row.id}>
            {row.getVisibleCells().map((cell) => (
              <TableCell key={cell.id}>
                {flexRender(cell.column.columnDef.cell, cell.getContext())}
              </TableCell>
            ))}
          </TableRow>
        ))}
      </TableBody>
    </Table>
  )
}

Why Use the Shadcn Data Table Component

  • Headless logic, your markup: TanStack Table handles state and row models while you keep full control of the HTML and Tailwind classes.
  • Feature by feature: Add sorting, filtering, pagination, selection or expansion only when you need them, keeping the bundle small.
  • Type safe columns: Column definitions are typed against your data, so accessor keys and cell renderers are checked by TypeScript.
  • Client or server data: Use the built-in row models for local data, or switch to manual sorting and pagination for server side results.
  • Composes with shadcn/ui: Checkboxes, dropdown menus, inputs and buttons from your own component folder slot directly into cells and toolbars.

Common Data Table Use Cases

  • Admin panels: Users, roles and permissions with search, bulk actions and pagination.
  • Orders and payments: Transaction lists with status, amount and expandable order details.
  • CRM records: Leads, contacts and deals with sortable columns and filters.
  • Inventory: Products and stock levels with inline edit and delete actions.
  • Prioritized lists: Backlogs or playlists where users reorder rows by dragging them.
  • Reports: Large datasets in a fixed height table with a sticky header.

Customizing the Shadcn Data Table

Because the table is regular markup, you customize it where it is rendered: change cell padding and alignment on TableCell, style selected rows with data-[state=selected], and put badges, avatars or menus inside cell renderers. Column level options such as enableSorting, enableHiding and size live in the column definition. Colors follow your theme tokens; build a palette with the free Theme Generator.

For example, this makes a column header sortable:

{
  accessorKey: "email",
  header: ({ column }) => (
    <Button
      variant="ghost"
      onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}
    >
      Email
      <ArrowUpDown />
    </Button>
  ),
}

Data Table Accessibility and Keyboard Support

The data table renders real table, th and td elements, so screen readers can announce column headers as users move between cells. Sort toggles are buttons, and the selection checkboxes carry aria-label values such as "Select all" and "Select row". Add a TableCaption or an aria-label on the table to describe what it lists.

Icon-only buttons for expanding, editing, deleting or dragging should always have a visually hidden label, as the variants here do. The draggable variants register the dnd-kit keyboard sensor, so a focused drag handle can be picked up with Space or Enter and moved with the arrow keys.

KeyAction
TabMoves focus to the next control: filter, sort button, checkbox or row action.
ShiftTabMoves focus to the previous control.
EnterActivates the focused sort, expand, action or pagination button, or picks up and drops a focused drag handle.
SpaceToggles the focused checkbox, or picks up and drops a focused drag handle.
ArrowUpMoves a picked up row up in the draggable rows variant.
ArrowDownMoves a picked up row down in the draggable rows variant.
ArrowLeftMoves a picked up column left in the draggable columns variant.
ArrowRightMoves a picked up column right in the draggable columns variant.
EscapeCancels a drag and restores the original order.

Data Table Best Practices

  • Right align numeric columns such as amounts so values are easy to compare.
  • Always render an empty state row, like No results, when filters match nothing.
  • Give each row a stable id with getRowId when rows can be selected, reordered or updated.
  • Keep the number of visible columns small by default and let users show more from a column menu.
  • Use server side pagination and filtering once the dataset grows beyond a few thousand rows.
  • For static data without interaction, use the plain Table instead.

Components Related to Data Table

Shadcn Data Table FAQ

Keep a SortingState in React state, pass it to useReactTable with onSortingChange and getSortedRowModel(), and render the column header as a button that calls column.toggleSorting(column.getIsSorted() === 'asc').

Add getFilteredRowModel() and a ColumnFiltersState to the table, then bind an input to table.getColumn('email')?.getFilterValue() and call setFilterValue on change. For a search across all columns, use the globalFilter state instead.

Set manualPagination: true and pass rowCount (or pageCount) to useReactTable, keep the pagination state in React, and fetch the matching page from your API whenever pageIndex or pageSize changes.

Table is a set of styled HTML table elements with no behavior. Data Table is a pattern that combines those elements with TanStack Table to add sorting, filtering, pagination, selection and other interactive features.

Keep an ExpandedState in useState and pass expanded, onExpandedChange and getRowCanExpand to useReactTable. Add a column with a chevron button that calls row.toggleExpanded(), then render a second TableRow with a single TableCell spanning columns.length whenever row.getIsExpanded() is true, grouping both rows in a React Fragment.

Looking for something else? Browse all shadcn/ui components or ready-made UI blocks built with them.