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.
Prerequisites
Section titled “Prerequisites”- A React application with TypeScript
- Tailwind CSS configured
- shadcn/ui initialized in the project
Add the registry component
Section titled “Add the registry component”npx shadcn@latest add https://virtuoso.dev/r/data-table.jsonThe 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.
Icon library
Section titled “Icon library”The wrapper uses lucide-react for the loading spinner, error icon, and the drag grip on the reorderable column header. 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:
data-table.tsx—Loader2(spinner),AlertCircle(error state)column-reorder/reorder-grip.tsx—GripVertical(drag handle)
Basic styled table
Section titled “Basic styled table”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>
)
}Next steps
Section titled “Next steps”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.