

# Table

Presentational semantic `<table>` for admin data grids. Use compound `Table.Header` / `Body` / `Row` / `Column` / `Cell` parts or a data-driven `columns` + `data` API.

## Examples

### Default

A simple two-column data table.

```tsx
import { Table } from '@var-ui/react';

<Table
  columns={[
    { key: 'name', header: 'Name', isRowHeader: true },
    { key: 'role', header: 'Role' },
  ]}
  data={[{ name: 'Ada', role: 'Admin' }]}
/>
```

```astro
<!-- No Astro binding yet — use @var-ui/react -->
```

```html
<!-- No HTML demo yet — use @var-ui/react -->
```

### Striped compact

Enable `isStriped` and `density="compact"` for denser rosters; add `caption` for an accessible table title.

```tsx
import { Table } from '@var-ui/react';

<Table
  isStriped
  density="compact"
  caption="Team roster"
  columns={[
    { key: 'name', header: 'Name', isRowHeader: true },
    { key: 'role', header: 'Role' },
    { key: 'status', header: 'Status' },
  ]}
  data={[
    { name: 'Ada', role: 'Admin', status: 'Active' },
    { name: 'Grace', role: 'Editor', status: 'Active' },
  ]}
/>
```

```astro
<!-- No Astro binding yet — use @var-ui/react -->
```

```html
<!-- No HTML demo yet — use @var-ui/react -->
```

## Props

| Name | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| caption | ReactNode | no |  |  |
| children | ReactNode | no |  |  |
| className | string \| undefined | no |  |  |
| columnOrder | string[] \| undefined | no |  | Column keys in display order — required with `columnWidths` for `<colgroup>`. |
| columns | TableColumnDef<T>[] \| undefined | no |  |  |
| columnWidths | Record<string, string> \| undefined | no |  | Explicit column widths keyed by column id. |
| data | T[] \| undefined | no |  |  |
| density | "compact" \| "balanced" \| "spacious" \| undefined | no |  |  |
| dividers | "grid" \| "none" \| "columns" \| "rows" \| undefined | no |  |  |
| emptyContent | ReactNode | no |  |  |
| getRowId | ((row: T) => string) \| undefined | no |  |  |
| hasHover | boolean \| undefined | no |  |  |
| isStriped | boolean \| undefined | no |  |  |
| layout | "fixed" \| "auto" \| undefined | no | 'auto' |  |
| onSortChange | ((next: SortDescriptor) => void) \| undefined | no |  |  |
| renderCell | ((column: TableColumnDef<T>, row: T) => ReactNode) \| undefined | no |  |  |
| sortDescriptor | SortDescriptor \| undefined | no |  |  |
| stickyHeader | boolean \| undefined | no |  |  |
| textOverflow | "wrap" \| "truncate" \| undefined | no |  |  |

## Accessibility

Renders a real `<table>`. Mark the identifying column with `isRowHeader` (`scope="row"`). Prefer a `caption` (or external heading referenced with `aria-labelledby`) so the table has an accessible name. Sort chrome sets `aria-sort` when you wire `allowsSorting` / `onSortChange`.
