# GridTable
> CSS Grid-based superset of Table for column grouping and content-based sizing.

## When to use

With [flexbox](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_flexible_box_layout)-based [Table](/components/tables/table), each row calculates its layout independently. **GridTable** uses [CSS Grid](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_grid_layout) for a single unified column track system across all rows.

Use **GridTable** when you need:

- Grouped headers spanning multiple columns
- Columns sized based on their widest content
- Precise, declarative column layout

## Import

```js
import {
  GridTable,
  createGridTemplate,
  getGridTemplateColumn
} from '@gemini-suite/vera-react';
```

**GridTable** is a compound component that consists of multiple parts which can be composed together to achieve the desired table interface:

- `GridTable.Root`: The wrapper that contains all the parts of a grid table. **Requires** `gridTemplateColumns` prop.
- `GridTable.Head`: The container that defines the head of the table's columns (equivalent of `<thead>` HTML element).
- `GridTable.Header`: A convenience container wrapping content into `GridTable.Head` with single `GridTable.Row` inside.
- `GridTable.ColumnHeader`: Renders the header cell of a column (equivalent of native `<th>` element). Supports `colSpan` for spanning multiple columns.
- `GridTable.ColumnHeaderContent`: Wrapper for column's header text contents.
- `GridTable.ColumnHeaderTitle`: Column's header title.
- `GridTable.ColumnHeaderSubtitle`: Column's header subtitle.
- `GridTable.ColumnResizeHandle`: The handle for resizing the column. Should be passed to `GridTable.ColumnHeader` via the `resizeHandle` prop.
- `GridTable.Body`: The container grouping a set of `GridTable.Row`s that are main content of the table (equivalent of native `<tbody>` element).
- `GridTable.Row`: Renders table row (equivalent of native `<tr>` element).
- `GridTable.Cell`: Cell to be placed in the `GridTable.Row` that displays single piece of data in the column (equivalent of native `<td>` element). Wraps text content into `GridTable.CellContent` automatically.
- `GridTable.CellContent`: Wrapper for cell's text contents.
- `GridTable.SelectionCell`: Composes `GridTable.Cell` and `GridTable.SelectionCellCheckbox`, to render a cell with checkbox for implementing selection of rows.
- `GridTable.SelectionCellCheckbox`: Customized [Checkbox](/components/forms/checkbox) component to be placed in the table cell.
- `GridTable.Foot`: The container grouping a set of `GridTable.Row`s which is placed at the bottom of the table (equivalent of native `<tfoot>` element).
- `GridTable.Footer`: A convenience container wrapping content into `GridTable.Foot` with single `GridTable.Row` inside.
- `GridTable.EmptyState`: The wrapper for providing additional context when the table data is either unavailable or nonexistent.

## Examples

<Callout variant="tip">

These examples focus on GridTable-specific features. For general table patterns, see [Table](/components/tables/table) which has the same component structure. Migration is straightforward: replace `Table` namespace with `GridTable` and move sizing props from cells to `gridTemplateColumns`.

</Callout>

### Basic

The `gridTemplateColumns` prop is **required**. You can pass any CSS `grid-template-columns` value directly, or use the [createGridTemplate](#creategridtemplate) utility for semantic column widths.

```jsx
() => {
  const data = [
    { id: 1, name: 'Torvald Halvor', office: 'Oslo', department: 'Trading' },
    { id: 2, name: 'Mikael Rikard', office: 'Berlin', department: 'Energy' },
    { id: 3, name: 'Ragnhild Tine', office: 'Munich', department: 'UX' },
    { id: 4, name: 'Jan Kowalski', office: 'Warsaw', department: 'Power Grid' }
  ];

  return (
    <GridTable.Root
      aria-label="Example grid table"
      gridTemplateColumns="48px repeat(3, minmax(0, 1fr))"
    >
      <GridTable.Header stickyOffset={0}>
        <GridTable.ColumnHeader>{'ID'}</GridTable.ColumnHeader>
        <GridTable.ColumnHeader>{'Name'}</GridTable.ColumnHeader>
        <GridTable.ColumnHeader>{'Office'}</GridTable.ColumnHeader>
        <GridTable.ColumnHeader>{'Department'}</GridTable.ColumnHeader>
      </GridTable.Header>
      <GridTable.Body>
        {data.map(row => (
          <GridTable.Row key={row.id}>
            <GridTable.Cell>{row.id}</GridTable.Cell>
            <GridTable.Cell>{row.name}</GridTable.Cell>
            <GridTable.Cell>{row.office}</GridTable.Cell>
            <GridTable.Cell>{row.department}</GridTable.Cell>
          </GridTable.Row>
        ))}
      </GridTable.Body>
    </GridTable.Root>
  );
};
```

### Column widths

**GridTable** supports several column width modes through the [createGridTemplate](#creategridtemplate) utility:

- **`grow`** (default): Fills available space. Min width is the width of the widest cell.
- **`growCollapse`**: Grows to fill space but can shrink below content width.
- **`auto`**: The column is the width of its widest cell.
- **Fixed values**: Will be exactly that width (e.g., `120`, `'200px'`, `'10rem'`).

Each mode can be combined with `minWidth` and `maxWidth` constraints.

```jsx
() => {
  const data = [
    {
      asset: 'Nordfjord Alpha',
      region: 'Northern Norway, NO4',
      updated: '2 hours ago',
      capacity: '120 MW',
      status: 'Online'
    },
    {
      asset: 'Lysebotn Hydro',
      region: 'Western Norway, NO5',
      updated: '4 days ago',
      capacity: '210 MW',
      status: 'Online'
    },
    {
      asset: 'Göteborg Solar',
      region: 'Sweden West, SE3',
      updated: '4 days ago',
      capacity: '45 MW',
      status: 'Offline'
    },
    {
      asset: 'Øresund Offshore',
      region: 'Denmark East, DK2',
      updated: '1 week ago',
      capacity: '350 MW',
      status: 'Maintenance'
    }
  ];

  const statusColor = {
    Online: 'success',
    Offline: 'danger',
    Maintenance: 'warning'
  };

  return (
    <GridTable.Root
      aria-label="Column widths example"
      gridTemplateColumns={createGridTemplate([
        { width: 'grow', maxWidth: 180 },
        { width: 'growCollapse', minWidth: '10rem' },
        { width: 'auto' },
        { width: 100 },
        { width: 'grow' }
      ])}
    >
      <GridTable.Header stickyOffset={0}>
        <GridTable.ColumnHeader>
          <GridTable.ColumnHeaderContent>
            <GridTable.ColumnHeaderTitle>{'Asset'}</GridTable.ColumnHeaderTitle>
            <GridTable.ColumnHeaderSubtitle>
              {'grow, max 180px'}
            </GridTable.ColumnHeaderSubtitle>
          </GridTable.ColumnHeaderContent>
        </GridTable.ColumnHeader>
        <GridTable.ColumnHeader>
          <GridTable.ColumnHeaderContent>
            <GridTable.ColumnHeaderTitle>
              {'Region'}
            </GridTable.ColumnHeaderTitle>
            <GridTable.ColumnHeaderSubtitle>
              {'growCollapse, min 10rem'}
            </GridTable.ColumnHeaderSubtitle>
          </GridTable.ColumnHeaderContent>
        </GridTable.ColumnHeader>
        <GridTable.ColumnHeader>
          <GridTable.ColumnHeaderContent>
            <GridTable.ColumnHeaderTitle>
              {'Updated'}
            </GridTable.ColumnHeaderTitle>
            <GridTable.ColumnHeaderSubtitle>
              {'auto'}
            </GridTable.ColumnHeaderSubtitle>
          </GridTable.ColumnHeaderContent>
        </GridTable.ColumnHeader>
        <GridTable.ColumnHeader align="right">
          <GridTable.ColumnHeaderContent>
            <GridTable.ColumnHeaderTitle>
              {'Capacity'}
            </GridTable.ColumnHeaderTitle>
            <GridTable.ColumnHeaderSubtitle>
              {'100px'}
            </GridTable.ColumnHeaderSubtitle>
          </GridTable.ColumnHeaderContent>
        </GridTable.ColumnHeader>
        <GridTable.ColumnHeader>
          <GridTable.ColumnHeaderContent>
            <GridTable.ColumnHeaderTitle>
              {'Status'}
            </GridTable.ColumnHeaderTitle>
            <GridTable.ColumnHeaderSubtitle>
              {'grow'}
            </GridTable.ColumnHeaderSubtitle>
          </GridTable.ColumnHeaderContent>
        </GridTable.ColumnHeader>
      </GridTable.Header>
      <GridTable.Body>
        {data.map((row, index) => (
          <GridTable.Row key={index}>
            <GridTable.Cell>{row.asset}</GridTable.Cell>
            <GridTable.Cell>{row.region}</GridTable.Cell>
            <GridTable.Cell>{row.updated}</GridTable.Cell>
            <GridTable.Cell align="right">{row.capacity}</GridTable.Cell>
            <GridTable.Cell>
              <Label variant="subtle" color={statusColor[row.status]}>
                {row.status}
              </Label>
            </GridTable.Cell>
          </GridTable.Row>
        ))}
      </GridTable.Body>
    </GridTable.Root>
  );
};
```

### Column groups

Use `colSpan` on `GridTable.ColumnHeader` to create grouped headers that span multiple columns. This is useful for organizing related columns under a common heading.

```jsx
() => {
  const data = [
    {
      contract: '14:00–15:00',
      spot: 142.19,
      bidQty: 0.4,
      bidPrice: 147.18,
      askPrice: 174.97,
      askQty: 0.4
    },
    {
      contract: '15:00–16:00',
      spot: 133.13,
      bidQty: 2.0,
      bidPrice: 142.7,
      askPrice: 155.42,
      askQty: 0.4
    },
    {
      contract: '16:00–17:00',
      spot: 143.06,
      bidQty: 0.4,
      bidPrice: 155.65,
      askPrice: 159.61,
      askQty: 8.1
    },
    {
      contract: '17:00–18:00',
      spot: 133.93,
      bidQty: 0.2,
      bidPrice: 160.43,
      askPrice: 166.01,
      askQty: 7.4
    }
  ];

  const formatPrice = value =>
    value.toLocaleString('en-GB', { minimumFractionDigits: 2 });
  const formatQty = value =>
    value.toLocaleString('en-GB', { minimumFractionDigits: 1 });

  return (
    <GridTable.Root
      aria-label="Column groups example"
      cellSize="small"
      gridTemplateColumns={createGridTemplate([
        { width: 'growCollapse', minWidth: 120 },
        { width: 'grow', maxWidth: 100 },
        { width: 'grow', maxWidth: 100 },
        { width: 'grow', maxWidth: 100 },
        { width: 'grow', maxWidth: 100 },
        { width: 'grow', maxWidth: 100 }
      ])}
    >
      <GridTable.Head stickyOffset={0}>
        <GridTable.Row>
          <GridTable.ColumnHeader showDivider isGroupHeader />
          <GridTable.ColumnHeader showDivider isGroupHeader />
          <GridTable.ColumnHeader
            colSpan={2}
            showDivider
            isGroupHeader
            align="center"
            css={{
              backgroundColor: '$backgroundSuccess',
              color: '$foregroundSuccess'
            }}
          >
            {'Bid'}
          </GridTable.ColumnHeader>
          <GridTable.ColumnHeader
            colSpan={2}
            isGroupHeader
            align="center"
            css={{
              backgroundColor: '$backgroundDanger',
              color: '$foregroundDanger'
            }}
          >
            {'Ask'}
          </GridTable.ColumnHeader>
        </GridTable.Row>
        <GridTable.Row>
          <GridTable.ColumnHeader showDivider>
            {'Contract'}
          </GridTable.ColumnHeader>
          <GridTable.ColumnHeader align="right" showDivider>
            <GridTable.ColumnHeaderContent>
              <GridTable.ColumnHeaderTitle>
                {'Spot'}
              </GridTable.ColumnHeaderTitle>
              <GridTable.ColumnHeaderSubtitle>
                {'EUR/MWh'}
              </GridTable.ColumnHeaderSubtitle>
            </GridTable.ColumnHeaderContent>
          </GridTable.ColumnHeader>
          <GridTable.ColumnHeader align="right">
            <GridTable.ColumnHeaderContent>
              <GridTable.ColumnHeaderTitle>{'Qty'}</GridTable.ColumnHeaderTitle>
              <GridTable.ColumnHeaderSubtitle>
                {'MW'}
              </GridTable.ColumnHeaderSubtitle>
            </GridTable.ColumnHeaderContent>
          </GridTable.ColumnHeader>
          <GridTable.ColumnHeader align="right" showDivider>
            <GridTable.ColumnHeaderContent>
              <GridTable.ColumnHeaderTitle>
                {'Price'}
              </GridTable.ColumnHeaderTitle>
              <GridTable.ColumnHeaderSubtitle>
                {'EUR/MWh'}
              </GridTable.ColumnHeaderSubtitle>
            </GridTable.ColumnHeaderContent>
          </GridTable.ColumnHeader>
          <GridTable.ColumnHeader>
            <GridTable.ColumnHeaderContent>
              <GridTable.ColumnHeaderTitle>
                {'Price'}
              </GridTable.ColumnHeaderTitle>
              <GridTable.ColumnHeaderSubtitle>
                {'EUR/MWh'}
              </GridTable.ColumnHeaderSubtitle>
            </GridTable.ColumnHeaderContent>
          </GridTable.ColumnHeader>
          <GridTable.ColumnHeader>
            <GridTable.ColumnHeaderContent>
              <GridTable.ColumnHeaderTitle>{'Qty'}</GridTable.ColumnHeaderTitle>
              <GridTable.ColumnHeaderSubtitle>
                {'MW'}
              </GridTable.ColumnHeaderSubtitle>
            </GridTable.ColumnHeaderContent>
          </GridTable.ColumnHeader>
        </GridTable.Row>
      </GridTable.Head>
      <GridTable.Body>
        {data.map((row, index) => (
          <GridTable.Row key={index}>
            <GridTable.Cell showDivider>{row.contract}</GridTable.Cell>
            <GridTable.Cell align="right" showDivider>
              {formatPrice(row.spot)}
            </GridTable.Cell>
            <GridTable.Cell align="right">
              {formatQty(row.bidQty)}
            </GridTable.Cell>
            <GridTable.Cell align="right" showDivider>
              {formatPrice(row.bidPrice)}
            </GridTable.Cell>
            <GridTable.Cell>{formatPrice(row.askPrice)}</GridTable.Cell>
            <GridTable.Cell>{formatQty(row.askQty)}</GridTable.Cell>
          </GridTable.Row>
        ))}
      </GridTable.Body>
    </GridTable.Root>
  );
};
```

### Content-based sizing

Use `auto` width to size a column to the width of its widest cell.

<Callout variant="tip">

Keep in mind that column width will change as content changes. For columns with highly variable content, prefer `grow` with constraints.

</Callout>

```jsx
() => {
  const alerts = [
    {
      id: 'ALT-001',
      message: 'Grid frequency deviation detected in NO1 region',
      source: 'FrequencyMonitor',
      category: 'Grid Operations',
      time: '14:32'
    },
    {
      id: 'ALT-002',
      message: 'Scheduled maintenance window starting for Nordfjord substation',
      source: 'MaintenanceScheduler',
      category: 'Maintenance',
      time: '14:28'
    },
    {
      id: 'ALT-003',
      message: 'High load warning',
      source: 'LoadBalancer',
      category: 'Grid Operations',
      time: '14:15'
    },
    {
      id: 'ALT-004',
      message: 'Renewable generation forecast updated',
      source: 'ForecastEngine',
      category: 'Forecasting',
      time: '13:58'
    },
    {
      id: 'ALT-005',
      message: 'Connection restored',
      source: 'NetworkMonitor',
      category: 'Network',
      time: '13:42'
    }
  ];

  return (
    <GridTable.Root
      aria-label="Content-based sizing example"
      rowSeparation="stripes"
      gridTemplateColumns={createGridTemplate([
        { width: 'auto' },
        { width: 'grow' },
        { width: 'auto' },
        { width: 'growCollapse', minWidth: 100 }
      ])}
    >
      <GridTable.Header stickyOffset={0}>
        <GridTable.ColumnHeader>
          <GridTable.ColumnHeaderContent>
            <GridTable.ColumnHeaderTitle>{'Time'}</GridTable.ColumnHeaderTitle>
            <GridTable.ColumnHeaderSubtitle>
              {'auto'}
            </GridTable.ColumnHeaderSubtitle>
          </GridTable.ColumnHeaderContent>
        </GridTable.ColumnHeader>
        <GridTable.ColumnHeader>
          <GridTable.ColumnHeaderContent>
            <GridTable.ColumnHeaderTitle>
              {'Message'}
            </GridTable.ColumnHeaderTitle>
            <GridTable.ColumnHeaderSubtitle>
              {'grow'}
            </GridTable.ColumnHeaderSubtitle>
          </GridTable.ColumnHeaderContent>
        </GridTable.ColumnHeader>
        <GridTable.ColumnHeader>
          <GridTable.ColumnHeaderContent>
            <GridTable.ColumnHeaderTitle>
              {'Source'}
            </GridTable.ColumnHeaderTitle>
            <GridTable.ColumnHeaderSubtitle>
              {'auto'}
            </GridTable.ColumnHeaderSubtitle>
          </GridTable.ColumnHeaderContent>
        </GridTable.ColumnHeader>
        <GridTable.ColumnHeader>
          <GridTable.ColumnHeaderContent>
            <GridTable.ColumnHeaderTitle>
              {'Category'}
            </GridTable.ColumnHeaderTitle>
            <GridTable.ColumnHeaderSubtitle>
              {'growCollapse'}
            </GridTable.ColumnHeaderSubtitle>
          </GridTable.ColumnHeaderContent>
        </GridTable.ColumnHeader>
      </GridTable.Header>
      <GridTable.Body>
        {alerts.map(row => (
          <GridTable.Row key={row.id}>
            <GridTable.Cell>{row.time}</GridTable.Cell>
            <GridTable.Cell>{row.message}</GridTable.Cell>
            <GridTable.Cell>{row.source}</GridTable.Cell>
            <GridTable.Cell>{row.category}</GridTable.Cell>
          </GridTable.Row>
        ))}
      </GridTable.Body>
    </GridTable.Root>
  );
};
```

When using `overflowStrategy="wrap"`, values with units can break across lines. Use non-breaking spaces (`\u00A0`) to keep them glued together. This is not needed with the default `truncate` strategy since content never wraps.

```jsx
// ❌ Regular space — can break across lines
`${value} MW`
// ✅ Non-breaking space
`${value}\u00A0MW`;
```

For values without a visible space (e.g., a currency symbol and number like `€100`), use `\u2060` (word joiner) to prevent breaks without adding space.

<Callout variant="tip">

If you format values with `Intl.NumberFormat`, the spaces it inserts are already non-breaking — no extra work needed. This only applies when manually concatenating values with units.

</Callout>

```jsx
() => {
  const formatMeasurement = (value, unit) =>
    `${value.toLocaleString('en-GB', { minimumFractionDigits: 2 })}\u00A0${unit}`;

  const sensors = [
    {
      id: 1,
      sensor: 'Turbine speed',
      reading: { value: 3450, unit: 'RPM' },
      location:
        'Upper machine hall, unit 3, north side bearing assembly monitored by vibration analysis system'
    },
    {
      id: 2,
      sensor: 'Water flow',
      reading: { value: 12500, unit: 'L/min' },
      location:
        'Intake channel between reservoir dam and penstock entry gate, downstream of trash rack filtration system'
    },
    {
      id: 3,
      sensor: 'Output',
      reading: { value: 245.8, unit: 'MW' },
      location:
        'Generator terminal at main step-up transformer connection point, high-voltage switchyard side'
    }
  ];

  return (
    <GridTable.Root
      aria-label="Non-breaking spaces example"
      overflowStrategy="wrap"
      alignY="top"
      gridTemplateColumns={createGridTemplate([
        { width: 'grow' },
        { width: 'auto' },
        { width: 'growCollapse', minWidth: 500 }
      ])}
    >
      <GridTable.Header stickyOffset={0}>
        <GridTable.ColumnHeader>
          <GridTable.ColumnHeaderContent>
            <GridTable.ColumnHeaderTitle>
              {'Sensor'}
            </GridTable.ColumnHeaderTitle>
          </GridTable.ColumnHeaderContent>
        </GridTable.ColumnHeader>
        <GridTable.ColumnHeader>
          <GridTable.ColumnHeaderContent>
            <GridTable.ColumnHeaderTitle>
              {'Reading'}
            </GridTable.ColumnHeaderTitle>
          </GridTable.ColumnHeaderContent>
        </GridTable.ColumnHeader>
        <GridTable.ColumnHeader>
          <GridTable.ColumnHeaderContent>
            <GridTable.ColumnHeaderTitle>
              {'Location'}
            </GridTable.ColumnHeaderTitle>
          </GridTable.ColumnHeaderContent>
        </GridTable.ColumnHeader>
      </GridTable.Header>
      <GridTable.Body>
        {sensors.map(row => (
          <GridTable.Row key={row.id}>
            <GridTable.Cell>{row.sensor}</GridTable.Cell>
            <GridTable.Cell>
              {formatMeasurement(row.reading.value, row.reading.unit)}
            </GridTable.Cell>
            <GridTable.Cell>{row.location}</GridTable.Cell>
          </GridTable.Row>
        ))}
      </GridTable.Body>
    </GridTable.Root>
  );
};
```

---

## Column layout utilities

Vera provides utility functions to easily construct `gridTemplateColumns` values.

### createGridTemplate

Converts an array of column configurations to a CSS `grid-template-columns` value.

```ts
import { createGridTemplate } from '@gemini-suite/vera-react';

createGridTemplate([
  { width: 'grow', minWidth: 100 },
  { width: 120 },
  { width: 'auto' }
]);
// Returns: "minmax(100px, 1fr) 120px auto"
```

### getGridTemplateColumn

Converts a single column configuration to a CSS value. Useful when building `gridTemplateColumns` dynamically.

```ts
import { getGridTemplateColumn } from '@gemini-suite/vera-react';

// Semantic modes
getGridTemplateColumn({ width: 'grow' }); // "minmax(max-content, 1fr)"
getGridTemplateColumn({ width: 'growCollapse' }); // "minmax(0, 1fr)"
getGridTemplateColumn({ width: 'auto' }); // "auto"

// Fixed widths
getGridTemplateColumn({ width: 120 }); // "120px"
getGridTemplateColumn({ width: '200px' }); // "200px"

// With constraints
getGridTemplateColumn({ width: 'grow', minWidth: 100 }); // "minmax(100px, 1fr)"
getGridTemplateColumn({ width: 'grow', maxWidth: 300 }); // "minmax(auto, 300px)"
getGridTemplateColumn({ width: 'grow', minWidth: 100, maxWidth: 300 }); // "minmax(100px, 300px)"
```

#### Quick reference

| Input                                      | Output                     |
| ------------------------------------------ | -------------------------- |
| `{ width: 'grow' }`                        | `minmax(max-content, 1fr)` |
| `{ width: 'growCollapse' }`                | `minmax(0, 1fr)`           |
| `{ width: 'auto' }`                        | `auto`                     |
| `{ width: 'auto', maxWidth: 200 }`         | `minmax(auto, 200px)`      |
| `{ width: 120 }`                           | `120px`                    |
| `{ width: '200px' }`                       | `200px`                    |
| `{ width: 'grow', minWidth: 100 }`         | `minmax(100px, 1fr)`       |
| `{ width: 'grow', maxWidth: 300 }`         | `minmax(auto, 300px)`      |
| `{ width: 'growCollapse', maxWidth: 200 }` | `minmax(0, 200px)`         |

---

## TanStack Table integration

**GridTable** works well with [TanStack Table](https://tanstack.com/table) for features like sorting, filtering, and column resizing. The key is generating `gridTemplateColumns` from TanStack's column state.

<Callout variant="tip">

GridTable shares the same patterns as Table. See [Table's TanStack integration](/components/tables/table#integration-with-tanstack-table) for more examples.

</Callout>

### Extending column meta

When using TypeScript, extend TanStack's `ColumnMeta` type to include semantic grid column width options:

```ts
import type { CSSProperties } from 'react';
import type { RowData } from '@tanstack/react-table';
import type { GridTableColumnWidth } from '@gemini-suite/vera-react';

declare module '@tanstack/react-table' {
  interface ColumnMeta<TData extends RowData, TValue> {
    gridWidth?: GridTableColumnWidth;
    minWidth?: CSSProperties['minWidth'];
    maxWidth?: CSSProperties['maxWidth'];
    showDivider?: boolean;
  }
}
```

### Generating gridTemplateColumns

Generate template columns from `table.getVisibleLeafColumns()`. You can extract a reusable hook (example below) or compute it directly in your component.

```ts
import { useMemo } from 'react';
import { useReactTable } from '@tanstack/react-table';
import { getGridTemplateColumn } from '@gemini-suite/vera-react';

type ResizeMode = 'fixed' | 'proportional';

function useGridTemplateColumns<TData>(
  table: ReturnType<typeof useReactTable<TData>>,
  resizeMode: ResizeMode = 'proportional'
) {
  return useMemo(() => {
    return table
      .getVisibleLeafColumns()
      .map(column => {
        // Optional: handle resizable columns
        if (column.getCanResize()) {
          const size = column.getSize();

          return resizeMode === 'fixed'
            ? `${size}px`
            : `minmax(${size}px, ${size}fr)`;
        }

        return getGridTemplateColumn({
          width: column.columnDef.meta?.gridWidth,
          minWidth: column.columnDef.meta?.minWidth,
          maxWidth: column.columnDef.meta?.maxWidth
        });
      })
      .join(' ');
  }, [
    table,
    // eslint-disable-next-line react-hooks/exhaustive-deps
    table.getState().columnSizing,
    // eslint-disable-next-line react-hooks/exhaustive-deps
    table.getState().columnSizingInfo,
    // eslint-disable-next-line react-hooks/exhaustive-deps
    table.getState().columnVisibility,
    resizeMode
  ]);
}
```

### Example with sorting and column groups

```js
import {
  flexRender,
  getCoreRowModel,
  getSortedRowModel,
  useReactTable,
  createColumnHelper
} from '@tanstack/react-table';
```

```jsx
() => {
  const [sorting, setSorting] = React.useState([]);

  const data = React.useMemo(
    () => [
      {
        id: 1,
        name: 'Torvald Halvor',
        email: 'torvald@example.com',
        department: 'Engineering',
        role: 'Developer'
      },
      {
        id: 2,
        name: 'Mikael Rikard',
        email: 'mikael@example.com',
        department: 'Design',
        role: 'UX Designer'
      },
      {
        id: 3,
        name: 'Ragnhild Tine',
        email: 'ragnhild@example.com',
        department: 'Engineering',
        role: 'Tech Lead'
      },
      {
        id: 4,
        name: 'Jan Kowalski',
        email: 'jan@example.com',
        department: 'Product',
        role: 'PM'
      }
    ],
    []
  );

  const columns = React.useMemo(() => {
    const columnHelper = createColumnHelper();

    return [
      columnHelper.accessor('id', {
        header: 'ID',
        cell: ({ getValue }) => (
          <GridTable.CellContent>{getValue()}</GridTable.CellContent>
        ),
        meta: { gridWidth: 60, showDivider: true },
        enableResizing: false
      }),
      columnHelper.group({
        id: 'personal',
        header: 'Personal',
        meta: { showDivider: true },
        columns: [
          columnHelper.accessor('name', {
            header: 'Name',
            cell: ({ getValue }) => (
              <GridTable.CellContent>{getValue()}</GridTable.CellContent>
            ),
            size: 200,
            minSize: 120,
            maxSize: 300
          }),
          columnHelper.accessor('email', {
            header: 'Email',
            cell: ({ getValue }) => (
              <GridTable.CellContent>{getValue()}</GridTable.CellContent>
            ),
            size: 220,
            minSize: 150,
            maxSize: 350,
            meta: { showDivider: true }
          })
        ]
      }),
      columnHelper.group({
        id: 'work',
        header: 'Work',
        columns: [
          columnHelper.accessor('department', {
            header: 'Department',
            cell: ({ getValue }) => (
              <GridTable.CellContent>{getValue()}</GridTable.CellContent>
            ),
            size: 150,
            minSize: 100,
            maxSize: 250
          }),
          columnHelper.accessor('role', {
            header: 'Role',
            cell: ({ getValue }) => (
              <GridTable.CellContent>{getValue()}</GridTable.CellContent>
            ),
            size: 150,
            minSize: 100,
            maxSize: 250
          })
        ]
      })
    ];
  }, []);

  const table = useReactTable({
    data,
    columns,
    state: { sorting },
    onSortingChange: setSorting,
    getCoreRowModel: getCoreRowModel(),
    getSortedRowModel: getSortedRowModel(),
    columnResizeMode: 'onChange'
  });

  const gridTemplateColumns = React.useMemo(() => {
    return table
      .getVisibleLeafColumns()
      .map(column => {
        if (column.getCanResize()) {
          const size = column.getSize();
          return `minmax(${size}px, ${size}fr)`;
        }

        return getGridTemplateColumn({
          width: column.columnDef.meta?.gridWidth,
          minWidth: column.columnDef.meta?.minWidth,
          maxWidth: column.columnDef.meta?.maxWidth
        });
      })
      .join(' ');
  }, [table, table.getState().columnSizing, table.getState().columnSizingInfo]);

  return (
    <GridTable.Root
      aria-label="TanStack integration example"
      gridTemplateColumns={gridTemplateColumns}
    >
      <GridTable.Head stickyOffset={0}>
        {table.getHeaderGroups().map(headerGroup => (
          <GridTable.Row key={headerGroup.id}>
            {headerGroup.headers.map(header => (
              <GridTable.ColumnHeader
                key={header.id}
                isGroupHeader={header.subHeaders.length > 0}
                colSpan={header.colSpan > 1 ? header.colSpan : undefined}
                showDivider={header.column.columnDef.meta?.showDivider}
                onClick={
                  !header.isPlaceholder && header.column.getCanSort()
                    ? header.column.getToggleSortingHandler()
                    : undefined
                }
                sort={
                  !header.isPlaceholder && header.column.getCanSort()
                    ? header.column.getIsSorted() || undefined
                    : undefined
                }
                resizeHandle={
                  header.column.getCanResize() ? (
                    <GridTable.ColumnResizeHandle
                      onMouseDown={header.getResizeHandler()}
                      onTouchStart={header.getResizeHandler()}
                      isResizing={header.column.getIsResizing()}
                    />
                  ) : undefined
                }
              >
                {header.isPlaceholder
                  ? null
                  : flexRender(
                      header.column.columnDef.header,
                      header.getContext()
                    )}
              </GridTable.ColumnHeader>
            ))}
          </GridTable.Row>
        ))}
      </GridTable.Head>
      <GridTable.Body>
        {table.getRowModel().rows.map(row => (
          <GridTable.Row key={row.id}>
            {row.getVisibleCells().map(cell => (
              <GridTable.Cell
                key={cell.id}
                showDivider={cell.column.columnDef.meta?.showDivider}
              >
                {flexRender(cell.column.columnDef.cell, cell.getContext())}
              </GridTable.Cell>
            ))}
          </GridTable.Row>
        ))}
      </GridTable.Body>
    </GridTable.Root>
  );
};
```

### Rows virtualization

Rendering large amounts of rows can be inefficient.
With [virtualization](https://tanstack.com/virtual/v3) (or windowing) of data, only currently visible rows are rendered to DOM to deliver best performance and user experience.

<Callout variant="tip">

When only a subset of rows are visible, it's a good practice to let all users know which
rows are being displayed.

Use the `aria-rowcount` attribute on the `GridTable.Root` to let assistive technologies know the total number of rows available. `GridTable.Row` should include `aria-rowindex` attribute to indicate where each row is in relation to the total available rows.

</Callout>

```js
import {
  flexRender,
  getCoreRowModel,
  useReactTable,
  createColumnHelper
} from '@tanstack/react-table';
import { useVirtualizer } from '@tanstack/react-virtual';
```

```jsx
() => {
  const columns = React.useMemo(() => {
    const columnHelper = createColumnHelper();

    return [
      columnHelper.accessor('name', {
        header: 'Host name',
        cell: ({ getValue }) => (
          <GridTable.CellContent>{getValue()}</GridTable.CellContent>
        ),
        meta: { gridWidth: 'grow', minWidth: 200 }
      }),
      columnHelper.accessor('ipAddress', {
        header: 'IP Address',
        cell: ({ getValue }) => (
          <GridTable.CellContent>{getValue()}</GridTable.CellContent>
        ),
        meta: { gridWidth: 'grow', minWidth: 140, maxWidth: 160 }
      }),
      columnHelper.accessor('port', {
        header: 'Port',
        cell: ({ getValue }) => (
          <GridTable.CellContent>{getValue()}</GridTable.CellContent>
        ),
        meta: { gridWidth: 'grow', minWidth: 80, maxWidth: 100 }
      }),
      columnHelper.accessor('status', {
        header: 'Status',
        meta: { gridWidth: 'grow', minWidth: 120, maxWidth: 160 },
        cell: ({ getValue }) => {
          const label = getValue();
          return (
            <Flex gap="spacingXs">
              <HintDot tone={label === 'Running' ? 'success' : 'danger'} />
              {label}
            </Flex>
          );
        }
      })
    ];
  }, []);

  const data = React.useMemo(
    () =>
      Array(5000)
        .fill()
        .map(() => ({
          name: faker.internet.domainName(),
          ipAddress: faker.internet.ip(),
          port: faker.internet.port(),
          status: faker.helpers.arrayElement(['Running', 'Down'])
        })),
    []
  );

  const table = useReactTable({
    data,
    columns,
    getCoreRowModel: getCoreRowModel()
  });

  const visibleColumns = table.getVisibleLeafColumns();

  const gridTemplateColumns = React.useMemo(
    () =>
      visibleColumns
        .map(column =>
          getGridTemplateColumn({
            width: column.columnDef.meta?.gridWidth,
            minWidth: column.columnDef.meta?.minWidth,
            maxWidth: column.columnDef.meta?.maxWidth
          })
        )
        .join(' '),
    [visibleColumns]
  );

  const scrollContainer = React.useRef(null);

  const rowVirtualizer = useVirtualizer({
    count: data.length,
    getScrollElement: () => scrollContainer.current,
    overscan: 5,
    estimateSize: () => 41
  });
  const { getTotalSize, getVirtualItems } = rowVirtualizer;

  const virtualRows = getVirtualItems();
  const tableRows = table.getRowModel().rows;

  const paddingTop = virtualRows.length > 0 ? virtualRows[0].start : 0;
  const paddingBottom =
    virtualRows.length > 0
      ? getTotalSize() - virtualRows[virtualRows.length - 1].end
      : 0;

  return (
    <GridTable.Root
      aria-label="Virtualized grid table"
      aria-rowcount={tableRows.length + 1}
      css={{ height: 400 }}
      ref={scrollContainer}
      gridTemplateColumns={gridTemplateColumns}
    >
      <GridTable.Head stickyOffset={0}>
        <GridTable.Row aria-rowindex={1}>
          {table.getFlatHeaders().map(header => (
            <GridTable.ColumnHeader key={header.id}>
              {header.isPlaceholder
                ? null
                : flexRender(
                    header.column.columnDef.header,
                    header.getContext()
                  )}
            </GridTable.ColumnHeader>
          ))}
        </GridTable.Row>
      </GridTable.Head>
      <GridTable.Body>
        {paddingTop > 0 ? (
          <div
            aria-hidden="true"
            key="offset-top"
            style={{ height: paddingTop, gridColumn: '1 / -1' }}
          />
        ) : null}
        {virtualRows.map(virtualRow => {
          const row = tableRows[virtualRow.index];

          return (
            <GridTable.Row key={row.id} aria-rowindex={virtualRow.index + 2}>
              {row.getVisibleCells().map(cell => (
                <GridTable.Cell key={cell.id}>
                  {flexRender(cell.column.columnDef.cell, cell.getContext())}
                </GridTable.Cell>
              ))}
            </GridTable.Row>
          );
        })}
        {paddingBottom > 0 ? (
          <div
            aria-hidden="true"
            key="offset-bottom"
            style={{ height: paddingBottom, gridColumn: '1 / -1' }}
          />
        ) : null}
      </GridTable.Body>
    </GridTable.Root>
  );
};
```

<Card
  href="https://next--698f15fa99e7b146f9002f64.chromatic.com/?path=/story/components-tables-gridtable--sorting-with-column-groups"
  title="See more TanStack examples in Storybook"
  actionIcon="externalLink"
/>

---

## API Reference

### GridTable.Root

| Name                      | Type                            | Default      | Description                                                                                                                                                                                                                                                             | Required |
| ------------------------- | ------------------------------- | ------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
| `css`                     | `StitchesCss`                   |              | Apply styles directly to a component in a similar way how you would define inline styles. Vera uses [Stitches](https://stitches.dev/) under the hood with a fully-typed API and support for features like tokens, media queries or variants.                            |          |
| `gridTemplateColumns`     | `string`                        |              | CSS `grid-template-columns` value that defines the column widths. Use `createGridTemplate` utility for type-safe column definitions.                                                                                                                                    | Yes      |
| `alignY`                  | `"center" \| "bottom" \| "top"` | `"center"`   | Vertical alignment of the content within table cells.                                                                                                                                                                                                                   |          |
| `cellSize`                | `"small" \| "medium"`           | `"medium"`   | Controls the size of the table's cells. `small` size helps to conserve space.                                                                                                                                                                                           |          |
| `overflowStrategy`        | `"wrap" \| "truncate"`          | `"truncate"` | Controls the overflow behavior for the text content of each cell.                                                                                                                                                                                                       |          |
| `highlightOnHover`        | `boolean`                       | `true`       | When `true`, rows will have hover color.                                                                                                                                                                                                                                |          |
| `syncScroll`              | `boolean`                       | `false`      | When `true`, table's row groups become scrolling containers instead of the `GridTable` and their scrolling position is synced up. Useful when you want to make `GridTable.Head` or `GridTable.Footer` "sticky" relative to the window as the user scrolls a long table. |          |
| `aria-label`              | `string`                        |              | Used to provide a better description of the table for users with assistive technologies.                                                                                                                                                                                | Yes      |
| `rowSeparation`           | `"dividers" \| "stripes"`       | `"dividers"` | Defines the appearance of row separation to aid users to distinguish rows.                                                                                                                                                                                              |          |
| `outlined`                | `boolean`                       | `true`       | Enable or disable table's outline.                                                                                                                                                                                                                                      |          |
| `addHorizontalWhitespace` | `boolean`                       | `false`      | When `true`, each first and last cell in a row gets additional left and right padding applied, equal to the whitespace between adjacent cells.                                                                                                                          |          |
| `showCellSeparation`      | `boolean`                       | `false`      | When `true`, there is a visible separation between table cells. Useful when using `rowSeparation="stripes"` together with `tone` on rows or cells.                                                                                                                      |          |
| `fitContent`              | `boolean`                       | `false`      | When `true`, the table width is set to `fit-content`, allowing the table to shrink to fit its content instead of filling the available width.                                                                                                                           |          |

### GridTable.Head

Container for header rows. Supports multiple `GridTable.Row` elements for grouped headers.

| Name           | Type          | Default | Description                                                                                                                                                                                                                                  | Required |
| -------------- | ------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
| `css`          | `StitchesCss` |         | Apply styles directly to a component in a similar way how you would define inline styles. Vera uses [Stitches](https://stitches.dev/) under the hood with a fully-typed API and support for features like tokens, media queries or variants. |          |
| `stickyOffset` | `number`      |         | Applies "sticky" positioning to the `GridTable.Head` with a defined offset against the top. When `scrollSync` is `true`, the offset is relative to nearest scrolling ancestor of the `GridTable`.                                            |          |

### GridTable.Header

Convenience wrapper that composes `GridTable.Head` with a single `GridTable.Row`.

| Name           | Type          | Default | Description                                                                                                                                                                                                                                  | Required |
| -------------- | ------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
| `css`          | `StitchesCss` |         | Apply styles directly to a component in a similar way how you would define inline styles. Vera uses [Stitches](https://stitches.dev/) under the hood with a fully-typed API and support for features like tokens, media queries or variants. |          |
| `stickyOffset` | `number`      |         | Applies "sticky" positioning to the `GridTable.Head` with a defined offset against the top. When `scrollSync` is `true`, the offset is relative to nearest scrolling ancestor of the `GridTable`.                                            |          |

### GridTable.ColumnHeader

Header cell for a column. Supports `colSpan` for grouped headers.

| Name            | Type                                      | Default  | Description                                                                                                                                                                                                                                  | Required |
| --------------- | ----------------------------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
| `css`           | `StitchesCss`                             |          | Apply styles directly to a component in a similar way how you would define inline styles. Vera uses [Stitches](https://stitches.dev/) under the hood with a fully-typed API and support for features like tokens, media queries or variants. |          |
| `align`         | `"center" \| "left" \| "right"`           | `"left"` | Text alignment of the content within the header cell.                                                                                                                                                                                        |          |
| `colSpan`       | `number`                                  |          | Number of columns this header spans. Used for grouped headers.                                                                                                                                                                               |          |
| `stickyOffset`  | `number`                                  |          | Applies "sticky" positioning to the `GridTable.ColumnHeader` with a defined offset. Positive values will offset the cell to the left. Negative values will offset the cell to the right.                                                     |          |
| `showDivider`   | `boolean`                                 |          | When `true`, the header cell renders a divider between it and the next header.                                                                                                                                                               |          |
| `onClick`       | `React.MouseEventHandler<HTMLDivElement>` |          | Event handler called when a user clicks the column header. Typically used to handle sorting.                                                                                                                                                 |          |
| `sort`          | `"asc" \| "desc"`                         |          | Defines column sorting direction. Indicates if items in a column are sorted in ascending or descending order. Sets `aria-sort` attribute.                                                                                                    |          |
| `sortIndicator` | `React.ReactElement`                      |          | `ReactElement` to render next to `GridTable.ColumnHeader` content as sorting indicator.                                                                                                                                                      |          |
| `resizeHandle`  | `React.ReactElement`                      |          | `ReactElement` to render as a column resize handle, typically a `GridTable.ColumnResizeHandle`.                                                                                                                                              |          |
| `isGroupHeader` | `boolean`                                 | `false`  | When `true`, reduces vertical padding for use in group header rows that span multiple columns.                                                                                                                                               |          |

### GridTable.ColumnHeaderContent

| Name               | Type                                                      | Default | Description                                                                                                                                                                                                                                                                                  | Required |
| ------------------ | --------------------------------------------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
| `as`               | `keyof JSX.IntrinsicElements \| React.ComponentType<any>` | `div`   | Change the component to a different HTML tag or custom component. This will merge the original component props with the props of the supplied element/component and change the underlying DOM node.   For more details, read our [Composition](/get-started/composition#polymorphism) guide. |          |
| `css`              | `StitchesCss`                                             |         | Apply styles directly to a component in a similar way how you would define inline styles. Vera uses [Stitches](https://stitches.dev/) under the hood with a fully-typed API and support for features like tokens, media queries or variants.                                                 |          |
| `overflowStrategy` | `"wrap" \| "truncate"`                                    |         | Controls the overflow behavior for the text content of the cell.                                                                                                                                                                                                                             |          |

### GridTable.ColumnHeaderTitle

| Name               | Type                                                      | Default | Description                                                                                                                                                                                                                                                                                  | Required |
| ------------------ | --------------------------------------------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
| `as`               | `keyof JSX.IntrinsicElements \| React.ComponentType<any>` | `span`  | Change the component to a different HTML tag or custom component. This will merge the original component props with the props of the supplied element/component and change the underlying DOM node.   For more details, read our [Composition](/get-started/composition#polymorphism) guide. |          |
| `css`              | `StitchesCss`                                             |         | Apply styles directly to a component in a similar way how you would define inline styles. Vera uses [Stitches](https://stitches.dev/) under the hood with a fully-typed API and support for features like tokens, media queries or variants.                                                 |          |
| `overflowStrategy` | `"wrap" \| "truncate"`                                    |         | Controls the overflow behavior for the text content of headers name.                                                                                                                                                                                                                         |          |

### GridTable.ColumnHeaderSubtitle

| Name               | Type                                                      | Default | Description                                                                                                                                                                                                                                                                                  | Required |
| ------------------ | --------------------------------------------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
| `as`               | `keyof JSX.IntrinsicElements \| React.ComponentType<any>` | `span`  | Change the component to a different HTML tag or custom component. This will merge the original component props with the props of the supplied element/component and change the underlying DOM node.   For more details, read our [Composition](/get-started/composition#polymorphism) guide. |          |
| `css`              | `StitchesCss`                                             |         | Apply styles directly to a component in a similar way how you would define inline styles. Vera uses [Stitches](https://stitches.dev/) under the hood with a fully-typed API and support for features like tokens, media queries or variants.                                                 |          |
| `overflowStrategy` | `"wrap" \| "truncate"`                                    |         | Controls the overflow behavior for the text content of headers unit.                                                                                                                                                                                                                         |          |

### GridTable.ColumnResizeHandle

| Name         | Type          | Default | Description                                                                                                                                                                                                                                  | Required |
| ------------ | ------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
| `css`        | `StitchesCss` |         | Apply styles directly to a component in a similar way how you would define inline styles. Vera uses [Stitches](https://stitches.dev/) under the hood with a fully-typed API and support for features like tokens, media queries or variants. |          |
| `isResizing` | `boolean`     | `false` | When `true`, the handle is in an active resizing state. Used to provide visual feedback during column resize operations.                                                                                                                     |          |

### GridTable.SortIndicator

| Name  | Type          | Default | Description                                                                                                                                                                                                                                  | Required |
| ----- | ------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
| `css` | `StitchesCss` |         | Apply styles directly to a component in a similar way how you would define inline styles. Vera uses [Stitches](https://stitches.dev/) under the hood with a fully-typed API and support for features like tokens, media queries or variants. |          |

### GridTable.Body

Container for the main content rows of the table.

| Name  | Type          | Default | Description                                                                                                                                                                                                                                  | Required |
| ----- | ------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
| `css` | `StitchesCss` |         | Apply styles directly to a component in a similar way how you would define inline styles. Vera uses [Stitches](https://stitches.dev/) under the hood with a fully-typed API and support for features like tokens, media queries or variants. |          |

### GridTable.Row

| Name            | Type                                             | Default | Description                                                                                                                                                                                                                                  | Required |
| --------------- | ------------------------------------------------ | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
| `css`           | `StitchesCss`                                    |         | Apply styles directly to a component in a similar way how you would define inline styles. Vera uses [Stitches](https://stitches.dev/) under the hood with a fully-typed API and support for features like tokens, media queries or variants. |          |
| `status`        | `"dragging" \| "dropTarget"`                     |         | Row `status` affecting it's visual style.                                                                                                                                                                                                    |          |
| `isHighlighted` | `boolean`                                        | `false` | When `true`, the row is visually highlighted.                                                                                                                                                                                                |          |
| `tone`          | `"danger" \| "success" \| "warning" \| "custom"` |         | Sets the status of the row.                                                                                                                                                                                                                  |          |

### GridTable.Cell

Cell for displaying data. Wraps text content into `GridTable.CellContent` automatically.

| Name           | Type                                             | Default      | Description                                                                                                                                                                                                                                  | Required |
| -------------- | ------------------------------------------------ | ------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
| `css`          | `StitchesCss`                                    |              | Apply styles directly to a component in a similar way how you would define inline styles. Vera uses [Stitches](https://stitches.dev/) under the hood with a fully-typed API and support for features like tokens, media queries or variants. |          |
| `align`        | `"center" \| "left" \| "right"`                  | `"left"`     | Text alignment of the content within the cell.                                                                                                                                                                                               |          |
| `stickyOffset` | `number`                                         |              | Applies "sticky" positioning to the `GridTable.Cell` with a defined offset. Positive values will offset the cell to the left. Negative values will offset the cell to the right.                                                             |          |
| `showDivider`  | `boolean`                                        |              | When `true`, the cell renders a divider between it and the next cell.                                                                                                                                                                        |          |
| `role`         | `"gridcell" \| "rowheader" \| "columnheader"`    | `"gridcell"` | [ARIA Role](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles) of the cell.                                                                                                                                              |          |
| `tone`         | `"danger" \| "success" \| "warning" \| "custom"` |              | Sets the status of the cell.                                                                                                                                                                                                                 |          |

### GridTable.CellContent

<Callout variant="tip">

In addition to the props below, you can pass [Text props](/components/typography/text#api-reference).

</Callout>

| Name               | Type                                                      | Default | Description                                                                                                                                                                                                                                                                                  | Required |
| ------------------ | --------------------------------------------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
| `as`               | `keyof JSX.IntrinsicElements \| React.ComponentType<any>` | `div`   | Change the component to a different HTML tag or custom component. This will merge the original component props with the props of the supplied element/component and change the underlying DOM node.   For more details, read our [Composition](/get-started/composition#polymorphism) guide. |          |
| `css`              | `StitchesCss`                                             |         | Apply styles directly to a component in a similar way how you would define inline styles. Vera uses [Stitches](https://stitches.dev/) under the hood with a fully-typed API and support for features like tokens, media queries or variants.                                                 |          |
| `overflowStrategy` | `"wrap" \| "truncate"`                                    |         | Controls the overflow behavior for the text content of the cell.                                                                                                                                                                                                                             |          |

### GridTable.SelectionCell

Composes `GridTable.Cell` and `GridTable.SelectionCellCheckbox` for row selection.

<Callout variant="tip">

In addition to the props below, you can pass all [GridTable.SelectionCellCheckbox props](#gridtableselectioncellcheckbox).

</Callout>

| Name           | Type                                          | Default    | Description                                                                                                                                                                                                                                  | Required |
| -------------- | --------------------------------------------- | ---------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
| `css`          | `StitchesCss`                                 |            | Apply styles directly to a component in a similar way how you would define inline styles. Vera uses [Stitches](https://stitches.dev/) under the hood with a fully-typed API and support for features like tokens, media queries or variants. |          |
| `align`        | `"center" \| "left" \| "right"`               | `"left"`   | Text alignment of the content within the cell.                                                                                                                                                                                               |          |
| `stickyOffset` | `number`                                      |            | Applies "sticky" positioning to the `GridTable.SelectionCell` with a defined offset. Positive values will offset the cell to the left. Negative values will offset the cell to the right.                                                    |          |
| `showDivider`  | `boolean`                                     |            | When `true`, the selection cell renders a divider between it and the next cell.                                                                                                                                                              |          |
| `role`         | `"gridcell" \| "rowheader" \| "columnheader"` | `gridcell` | [ARIA Role](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles) of the selection cell.                                                                                                                                    |          |
| `aria-label`   | `string`                                      |            | Used to provide a better description of the checkbox control for users with assistive technologies.                                                                                                                                          | Yes      |

### GridTable.SelectionCellCheckbox

<Callout variant="tip">

In addition to the props below, you can pass all [Checkbox props](/components/forms/checkbox#checkbox).

</Callout>

| Name         | Type          | Default | Description                                                                                                                                                                                                                                  | Required |
| ------------ | ------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
| `css`        | `StitchesCss` |         | Apply styles directly to a component in a similar way how you would define inline styles. Vera uses [Stitches](https://stitches.dev/) under the hood with a fully-typed API and support for features like tokens, media queries or variants. |          |
| `aria-label` | `string`      |         | Used to provide a better description of the checkbox control for users with assistive technologies.                                                                                                                                          | Yes      |

### GridTable.Foot

Container for footer rows.

| Name           | Type          | Default | Description                                                                                                                                                                                                                                  | Required |
| -------------- | ------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
| `css`          | `StitchesCss` |         | Apply styles directly to a component in a similar way how you would define inline styles. Vera uses [Stitches](https://stitches.dev/) under the hood with a fully-typed API and support for features like tokens, media queries or variants. |          |
| `stickyOffset` | `number`      |         | Applies "sticky" positioning to the `GridTable.Foot` with a defined offset against the bottom. When `scrollSync` is `true`, the offset is relative to nearest scrolling ancestor of the `GridTable`.                                         |          |

### GridTable.Footer

Convenience wrapper that composes `GridTable.Foot` with a single `GridTable.Row`.

| Name           | Type          | Default | Description                                                                                                                                                                                                                                  | Required |
| -------------- | ------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
| `css`          | `StitchesCss` |         | Apply styles directly to a component in a similar way how you would define inline styles. Vera uses [Stitches](https://stitches.dev/) under the hood with a fully-typed API and support for features like tokens, media queries or variants. |          |
| `stickyOffset` | `number`      |         | Applies "sticky" positioning to the `GridTable.Foot` with a defined offset against the bottom. When `scrollSync` is `true`, the offset is relative to nearest scrolling ancestor of the `GridTable`.                                         |          |

### GridTable.EmptyState

| Name  | Type          | Default | Description                                                                                                                                                                                                                                  | Required |
| ----- | ------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
| `css` | `StitchesCss` |         | Apply styles directly to a component in a similar way how you would define inline styles. Vera uses [Stitches](https://stitches.dev/) under the hood with a fully-typed API and support for features like tokens, media queries or variants. |          |
