Skip to content

Install The Headless Package

The headless package gives you VirtuosoDataTable, Column, ColumnHeader, and Cell without any preset styling. Pick it when you already have a design system, use non-Tailwind styling, or need fully custom markup around the table.

pnpm add @virtuoso.dev/data-table

npm, yarn, and bun work too.

The package ships layout defaults (column sizing, box model) in a @layer virtuoso block. Import the stylesheet once in your app’s CSS or entry point:

@import '@virtuoso.dev/data-table/styles.css';
import '@virtuoso.dev/data-table/styles.css'

The @layer virtuoso wrapping puts these rules at the lowest cascade priority, so any plain CSS or Tailwind utility class overrides them.

import { Cell, Column, ColumnHeader, VirtuosoDataTable, localModel } from '@virtuoso.dev/data-table'

import { rows } from './data'

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

const model = localModel({ data: rows })

export default function App() {
  return (
    <VirtuosoDataTable
      model={model}
      style={{
        height: 360,
        border: '1px solid var(--border)',
        borderRadius: 16,
        overflow: 'hidden',
      }}
    >
      <Column field="name">
        <ColumnHeader>
          {() => <div style={{ padding: '0 12px', fontWeight: 600, height: 44, display: 'flex', alignItems: 'center' }}>Product</div>}
        </ColumnHeader>
        <Cell>
          {({ cellValue }) => (
            <div style={{ padding: '0 12px', height: 44, display: 'flex', alignItems: 'center' }}>{String(cellValue)}</div>
          )}
        </Cell>
      </Column>
      <Column field="category">
        <ColumnHeader>
          {() => <div style={{ padding: '0 12px', fontWeight: 600, height: 44, display: 'flex', alignItems: 'center' }}>Category</div>}
        </ColumnHeader>
        <Cell>
          {({ cellValue }) => (
            <div style={{ padding: '0 12px', height: 44, display: 'flex', alignItems: 'center' }}>{String(cellValue)}</div>
          )}
        </Cell>
      </Column>
      <Column field="price">
        <ColumnHeader>
          {() => (
            <div
              style={{ padding: '0 12px', fontWeight: 600, height: 44, display: 'flex', alignItems: 'center', justifyContent: 'flex-end' }}
            >
              Price
            </div>
          )}
        </ColumnHeader>
        <Cell>
          {({ cellValue }) => (
            <div
              style={{
                padding: '0 12px',
                height: 44,
                display: 'flex',
                alignItems: 'center',
                justifyContent: 'flex-end',
                fontVariantNumeric: 'tabular-nums',
              }}
            >
              {currency.format(Number(cellValue))}
            </div>
          )}
        </Cell>
      </Column>
    </VirtuosoDataTable>
  )
}

The headless package exposes the full surface area: local and remote data models, instance control, scroll control, and testing utilities. Continue with data model and columns.