Basic Table Example
Three columns, a hardcoded product list, and the styled shadcn wrapper. The shape you’ll arrive at on day one when you drop the table into a screen, before any backend wiring, sorting, or pinning enters the picture.
The purpose of this example is to fix that day-one shape. The data array is passed to localModel; each <DataTableColumn> declares a field and the cell renderer for that field. Nothing is lifted into React state — the table owns its own scroll, selection, and layout state through the engine, and the column declarations live alongside the markup that uses them. Every later example in this section adds one capability on top of this skeleton; if anything below ever feels too dense, this is the page to return to.
APIs used
Section titled “APIs used”DataTablefor scrolling and virtualizationDataTableColumnfor declarative columnsDataTableColumnHeaderandDataTableCellfor presentation
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">{({ row }) => row.data.name}</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>
</DataTable>
)
}What this leaves out
Section titled “What this leaves out”- Grouped rows — add
groupsmarkers and aGroupHeaderCell - Sticky pinning — add
sticky="left"orsticky="right" - Remote data — swap
localModelforremoteModel - Stable row identity — add
computeRowKeyonce rows can sort, filter, or move