Skip to content

Install With shadcn/ui

The shadcn registry copies a DataTable wrapper into @/components/ui/data-table. The wrapper re-exports the headless engine from @virtuoso.dev/data-table and ships pre-styled DataTable, DataTableColumn, DataTableColumnHeader, and DataTableCell. You edit the wrapper; the headless package stays installed as a dependency.

  • A React application with TypeScript
  • Tailwind CSS configured
  • shadcn/ui initialized in the project
  • Path aliases resolvable from the root config shadcn reads. If a project uses a solution-style root tsconfig.json that only contains references, mirror the @/* path mapping there or shadcn may create a literal @/components/... directory instead of writing into src/components/....
npx shadcn@latest add petyosi/react-virtuoso/data-table

The command writes the wrapper to @/components/ui/data-table and imports @virtuoso.dev/data-table/styles.css (structural layout defaults). No extra CSS setup is needed.

Feature-specific wrapper components use the same GitHub registry address. For example, add the resize handle when you enable column resizing:

npx shadcn@latest add petyosi/react-virtuoso/data-table-resize-handle

Add the sort header button when sortable column headers should dispatch model actions:

npx shadcn@latest add petyosi/react-virtuoso/data-table-sort-header-button

The hosted registry URL still works if you prefer the existing virtuoso.dev registry endpoint:

npx shadcn@latest add https://virtuoso.dev/r/data-table.json

The wrapper uses lucide-react for the loading spinner, error icon, drag grip, and sort button icons. The npx shadcn add command installs lucide-react as a dependency on first run.

shadcn’s iconLibrary field in components.json only rewrites icon imports for the canonical shadcn registry — it does not touch components from third-party registries like ours. If your project uses a different icon set (@radix-ui/react-icons, phosphor-react, etc.) and you want the table icons to match, open the installed files under @/components/ui/data-table and swap the lucide imports for your library’s equivalents. The icons appear in:

  • index.tsxLoader2 (spinner), AlertCircle (error state)
  • column-reorder/reorder-grip.tsxGripVertical (drag handle)
  • column-sort/sort-header-button.tsxArrowUpDown, ArrowUp, ArrowDown (sort state)
import { DataTable, DataTableCell, DataTableColumn, DataTableColumnHeader } from '@/components/ui/data-table'

import { products } from './data'
import { localModel } from '@virtuoso.dev/data-table'

const currency = new Intl.NumberFormat('en-US', {
  currency: 'USD',
  style: 'currency',
})

const model = localModel({ data: products })

export default function App() {
  return (
    <DataTable className="rounded-xl" model={model} style={{ height: 360 }}>
      <DataTableColumn field="name">
        <DataTableColumnHeader>Product</DataTableColumnHeader>
        <DataTableCell className="font-medium">{({ cellValue }) => String(cellValue)}</DataTableCell>
      </DataTableColumn>
      <DataTableColumn field="category">
        <DataTableColumnHeader>Category</DataTableColumnHeader>
        <DataTableCell>{({ cellValue }) => String(cellValue)}</DataTableCell>
      </DataTableColumn>
      <DataTableColumn field="price">
        <DataTableColumnHeader className="justify-end">Price</DataTableColumnHeader>
        <DataTableCell className="text-right tabular-nums">{({ cellValue }) => currency.format(Number(cellValue))}</DataTableCell>
      </DataTableColumn>
      <DataTableColumn field="stock">
        <DataTableColumnHeader className="justify-end">Stock</DataTableColumnHeader>
        <DataTableCell className="text-right tabular-nums">{({ cellValue }) => String(cellValue)}</DataTableCell>
      </DataTableColumn>
    </DataTable>
  )
}

The wrapper picks up your shadcn theme automatically (border radius, color tokens, typography). Edit @/components/ui/data-table directly for custom row hover states, sticky backgrounds, or denser spacing.

The two required setup steps after installation are data model and columns. For an inventory of what npx shadcn add actually wrote into your project and how to edit it, see The shadcn Wrapper; for per-instance visual changes, see Styling.

Remote models, sticky columns, and instance control all import from @virtuoso.dev/data-table directly while the wrapper continues to provide the styled DataTable.