

## Overview [#overview]

Cell spanning changes how cells are presented without changing the row model or
source records.

| Span    | Use for                                            | Configure with |
| ------- | -------------------------------------------------- | -------------- |
| Columns | Full-width labels, summaries, or section rows.     | `spanColumns`  |
| Rows    | Repeated values shared by adjacent displayed rows. | `spanRows`     |

Spans work with every interaction mode. Column spans support row
virtualization. Row spans require adjacent rows to be mounted together, so set
`rowVirtualization="never"` on a known-small grid that uses `spanRows`. DataGrid
reports a configuration error when row spanning and row virtualization are both
active.

## Examples [#examples]

### Rows and columns [#rows-and-columns]

Use resolver functions when the span depends on the current row. Row spanning
merges adjacent displayed rows only; it does not sort or group the data.

<Tabs items="['Preview', 'Code']">
  <Tab value="Preview">
    <Preview name="DataGridCellSpanningScenario" />
  </Tab>

  <Tab value="Code">
    ```tsx
    const columns = columnHelper.columns([
      columnHelper.accessor("phase", {
        header: "Phase",
        meta: { rowHeader: true },
        spanColumns: ({ row }) => (row.original.summary ? 3 : 1),
        spanRows: ({ anchorRow, row }) =>
          !anchorRow.original.summary &&
          !row.original.summary &&
          anchorRow.original.phase === row.original.phase,
      }),
      columnHelper.accessor("item", { header: "Work item" }),
      columnHelper.accessor("owner", { header: "Owner" }),
    ]);

    <DataGrid table={table}>
      <DataGrid.Viewport
        aria-label="Work allocation with cell spans"
        rowVirtualization="never"
      />
    </DataGrid>
    ```
  </Tab>
</Tabs>

Set `spanRows: true` to merge adjacent cells whose values are equal. A
`spanRows` resolver can compare each candidate row with the run's anchor row.
`spanColumns` counts visible columns from the current cell; use `Infinity` to
span the rest of its current pinned region.

## API Reference [#api-reference]

### Table options [#table-options]

| Option               | Type      | Default | Description                              |
| -------------------- | --------- | ------- | ---------------------------------------- |
| `enableCellSpanning` | `boolean` | `true`  | Enables configured row and column spans. |

### Column options [#column-options]

| Option               | Type                                | Default | Description                                                                                       |
| -------------------- | ----------------------------------- | ------- | ------------------------------------------------------------------------------------------------- |
| `enableCellSpanning` | `boolean`                           | `true`  | Allows cells in the column to span rows or columns.                                               |
| `spanColumns`        | `number \| ((context) => number)`   | `1`     | Sets how many visible columns the cell occupies. Values are limited to the current pinned region. |
| `spanRows`           | `boolean \| ((context) => boolean)` | `false` | Merges adjacent displayed rows by equal value or a predicate.                                     |

### Resolver context [#resolver-context]

| Option        | Context                                                                      | Description                                              |
| ------------- | ---------------------------------------------------------------------------- | -------------------------------------------------------- |
| `spanColumns` | `row`, `column`, `table`                                                     | Resolve a column span from the current cell.             |
| `spanRows`    | `anchorRow`, `anchorValue`, `previousRow`, `row`, `value`, `column`, `table` | Decide whether the candidate row joins the current span. |
