Skip to content

Basics

Loading example…

There are three levels of taking over the markup, and most projects need only the first.

Unstyled. unstyled drops the presentational CSS and keeps the structural rules: sticky positioning, pinned offsets, the scroll container. You get a correct table with no opinions about how it looks.

<DataTable unstyled slots={designSystemSlots} data={rows} columns={columns} />

Primitives. Six slots, Button, IconButton, Checkbox, Select, TextInput and Menu, account for nearly every control in the table. Replacing those is what makes an adapter small:

export const designSystemSlots = {
  Button: DsButton,
  IconButton: DsIconButton,
  Checkbox: DsCheckbox,
  Select: DsSelect,
  TextInput: DsTextField,
  Menu: DsMenu,
};

Layout. When the arrangement itself is wrong (search in the page header, filters in a sidebar, pagination in a sticky footer), use DataTable.Root and the composable parts. The table instance is shared, so every piece stays in sync:

const table = useDataTable({ data, columns });

<DataTable.Root table={table}>
  <DataTable.Search table={table} />
  <DataTable.Table />
  <DataTable.Pagination />
</DataTable.Root>;

Shared defaults

TableDefaultsProvider applies slots, localization, icons and handlers to every table beneath it, so an adapter is configured once for an application rather than per table. Props on a table still win over the provider.

All the way down

If even the table element is wrong for what you are building (cards, a list, a chart), headless keeps the engine and gives up the rendering entirely.

Customization

The levels compose. An adapter usually means: unstyled, the six primitives, the provider, and tokens for what is left. That is a file, not a fork.

Limitations

  • Unstyled is not style-free. The structural rules remain, because sticky headers and pinned columns are layout, not decoration.
  • Composable parts still need the instance. They are not context-free; passing the table is what keeps them consistent.
  • Replacing primitives replaces their accessibility too. A Checkbox that does not support the indeterminate state breaks tri-state select-all.

API

  • DataTableProps: unstyled, slots, slotProps, classNames, styles, handlers, icons, localization.
  • TableSlots: the full list, primitives included.
  • Hooks: useDataTable for the composable form.