Askr documentation
UI & Components

Data Table

Data Table: anatomy, keyboard behavior, state, and theming in Askr.

Example

import { For } from '@askrjs/askr';
import { DataTable, Table, TableBody, TableCell, TableHead, TableHeaderCell, TableRow } from '@askrjs/themes/components';

<DataTable>
  <Table>
    <TableHead><TableRow><TableHeaderCell>Name</TableHeaderCell><TableHeaderCell>Status</TableHeaderCell></TableRow></TableHead>
    <TableBody>
      <For each={projects} by={(project) => project.id}>
        {(project) => <TableRow><TableCell>{project.name}</TableCell><TableCell>{project.status}</TableCell></TableRow>}
      </For>
    </TableBody>
  </Table>
</DataTable>

Purpose

Data Table is the themed composition layer over Table: it takes the same semantic parts and wires in the presentational conventions an application table usually needs, so you are not rebuilding header, body, and cell styling per feature. It is typed loosely against the shared catalog prop shape rather than a bespoke column API, so treat the composition on this page as the contract and keep sorting, filtering, and pagination state in your own application code, where the URL or server can own it.

Install and import

@askrjs/themes/data-table is the only place this component exists; behind the scenes that subpath, like /table and /scroll-area, just resolves to the shared dist/components.js barrel rather than shipping as its own module. Pull in @askrjs/themes/default too, since that's where the actual CSS comes from. A headless @askrjs/ui/data-table primitive isn't part of the picture — there's no independent behavior here to strip styling away from. Treat it as a companion to Table rather than a replacement for it.

Live examples

In practice Data Table wraps a Table the way Card wraps arbitrary content: <DataTable><Table>...</Table></DataTable> gives you a bordered, surfaced container around ordinary table markup. It doesn't accept rows, columns, or any data-shaped prop — everything between its tags renders as-is, so the actual table structure still comes from @askrjs/ui/table or @askrjs/themes/table.

Anatomy

Under the hood, Data Table is a single call to an internal catalogPart helper: it renders one div with data-slot="data-table" by default, and nothing else — no header slot, no toolbar slot, no pagination slot. Whatever you pass as children renders directly inside that div, so internal structure is entirely up to you and whatever Table markup you nest inside.

State model

As a styling wrapper rather than a data grid, Data Table doesn't track sorting, filtering, selection, or pagination internally. Whatever state a 'data table' implies elsewhere — sort column, selected rows, current page — you'll need to own in your own component and feed in through what you render as children. The component itself stays state-free.

Keyboard and accessibility

There's no keyboard handling to document because Data Table adds no interactive behavior of its own — it's a plain div. Accessibility for the table comes entirely from the Table primitives nested inside it (TableHeaderCell for headers, TableCaption for a description), exactly as if you'd used Table standalone.

Styling and tokens

The component's whole job is applying [data-slot="data-table"] styling: a 1px border in --ak-color-border, --ak-radius-lg corners, and an --ak-color-surface background, so a Table dropped inside reads as a distinct card-like region instead of blending into the page. It accepts an as prop to render a different element than div and an asChild prop to merge that styling onto a single child element instead.

API

Data Table's props type is CatalogComponentProps: an open Record<string, unknown> plus as?: CatalogElement, asChild?: boolean, children?: unknown, class?: string, and ref?: Ref<HTMLElement>. There's no columns, rows, sortState, or onSortChange prop despite the name — treat it as a styled Box specialized for tabular content, not a grid component.

Edge cases

Because Data Table accepts arbitrary children, nothing stops you from putting non-table content inside it — the border and surface styling still applies, which can be useful for a bordered panel that just happens to want the data-table visual treatment, though it's worth keeping the component name aligned with actual intent in your code. If you need real grid behavior — windowing, row selection, keyboard navigation across cells — none of that exists here or in the underlying Table primitives; that functionality lives in Virtual Table instead.

See Table for the headless and themed primitives that typically go inside a Data Table. See Card for the more general-purpose bordered-surface wrapper Data Table is styled similarly to. See Virtual Table if you actually need windowed rendering, row selection, or scroll state — Data Table provides none of that.