---
title: "Tables"
description: "A table and a chart can turn into each other, and a chart or a diagram can follow a table in the same document as it is edited."
canonical_url: "https://tiptap.dev/docs/diagrams/data/tables"
---

# Tables

A table and a chart can turn into each other, and a chart or a diagram can follow a table in the same document as it is edited.

## Quick start

With `chart.linkTables` on, place the selection in a table and call:

```ts
editor.commands.insertLinkedChart({ type: 'bar' })
```

Every edit of the table updates the chart in the same Transaction.

## How the table is read

`insertLinkedChart`, `linkChartToTable` and `updateLinkedTable` take `header` and `range`.

| Option          | Type                                 | Description                                                                                              |
| --------------- | ------------------------------------ | -------------------------------------------------------------------------------------------------------- |
| `header`        | `'auto' \| 'first-row' \| 'none'`    | Where the column names are. Default `'auto'`                                                             |
| `range.rows`    | `{ from?, to? }` or an array of them | The data rows read, counted from 0 below the header                                                      |
| `range.columns` | `(number \| { from?, to? })[]`       | The columns read, counted from 0, such as `[0, { from: 2 }]`. The first column read names the categories |

| `header`      | The column names                                                                           |
| ------------- | ------------------------------------------------------------------------------------------ |
| `'auto'`      | The first row, when it is made of header cells or holds no number outside the first column |
| `'first-row'` | The first row, whatever it holds                                                           |
| `'none'`      | Every row is data; the columns get default names                                           |

- **Both ends** of a range are included.
- **A negative number** counts from the end: `-1` is the last row, so `{ to: -2 }` leaves out a
  total row.
- **Empty rows** are not counted.
- **Several ranges** are read in the order given.
- **A row or column named twice** is read once.
- **Without `range`**, a selection of cells in the table is the range: the rows and columns it
  covers, with the first column of the table as the label.
- **`header` and `range` are stored** in the chart's Data Source address and apply to every
  later edit of the table.

## Commands

Turn a table into a chart and back, or a chart into an image that keeps its data:

> **Interactive demo:** [DiagramsConversions](https://embed-pro.tiptap.dev/preview/Extensions/DiagramsConversions)

### convertTableToChart

Replaces the table at the selection with a chart of its data.

```ts
editor.commands.convertTableToChart({ type: 'bar' })
```

| Option | Type        | Description                                            |
| ------ | ----------- | ------------------------------------------------------ |
| `type` | `ChartType` | The chart type. Defaults to `chart.defaultType`        |
| `pos`  | `number`    | A position inside the table. Defaults to the selection |

Returns `false` without a table.

### convertChartToTable

Replaces a chart with a plain table of its data.

```ts
editor.commands.convertChartToTable()
```

| Option | Type     | Description                                          |
| ------ | -------- | ---------------------------------------------------- |
| `pos`  | `number` | The chart's position. Defaults to the selected chart |

Returns `false` without a table in the Schema.

### insertLinkedChart

Inserts a chart that follows a table: every edit of the table updates the chart in the same
Transaction.

```ts
editor.commands.insertLinkedChart({
  table: editor.storage.diagrams.listTables()[0].pos,
  type: 'bar',
  columns: { label: 'Month', series: ['Retail'] },
})

// A table without a header, without its last row
editor.commands.insertLinkedChart({
  table,
  header: 'none',
  range: { rows: { to: -2 } },
  columns: { label: 0, series: [2] },
})

// The first and the last two rows, and only the columns 0, 3 and 4
editor.commands.insertLinkedChart({
  table,
  range: { rows: [{ to: 0 }, { from: -2 }], columns: [0, { from: 3, to: 4 }] },
})
```

| Option    | Type                                                          | Description                                                                                        |
| --------- | ------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- |
| `type`    | `ChartType`                                                   | The chart type. Defaults to `chart.defaultType`                                                    |
| `table`   | `number`                                                      | The table's position, from `listTables()`. Defaults to the table at the selection                  |
| `columns` | `{ label?: string \| number, series?: (string \| number)[] }` | Columns by the text of their header cell or by their position from 0                               |
| `header`  | `'auto' \| 'first-row' \| 'none'`                             | See [How the table is read](https://tiptap.dev/docs/diagrams/data/tables.md#how-the-table-is-read) |
| `range`   | `{ rows?, columns? }`                                         | See [How the table is read](https://tiptap.dev/docs/diagrams/data/tables.md#how-the-table-is-read) |
| `title`   | `string`                                                      | The chart's title                                                                                  |
| `below`   | `boolean`                                                     | `false` places the chart above the table. Default `true`                                           |

- **`columns.label`** is the column that names the categories.
- **`columns.series`** are the columns drawn.
- **Positions** also work for a table without a header.
- **Positions count** among the columns `range` reads.
- **Without `columns`**, the first column is the label and every other column is drawn.
- **The chart's data** is read-only while linked.
- Needs the option `chart.linkTables`.

Returns `false` when a name is not in the header or a position not in the table.

### updateLinkedTable

Changes how a chart or a diagram reads the table it follows, and reads it again.

```ts
editor.commands.updateLinkedTable({ header: 'none' })
editor.commands.updateLinkedTable({ header: undefined, range: { rows: { from: 1 } } })
```

| Option   | Type                              | Description                                                                                        |
| -------- | --------------------------------- | -------------------------------------------------------------------------------------------------- |
| `header` | `'auto' \| 'first-row' \| 'none'` | See [How the table is read](https://tiptap.dev/docs/diagrams/data/tables.md#how-the-table-is-read) |
| `range`  | `{ rows?, columns? }`             | See [How the table is read](https://tiptap.dev/docs/diagrams/data/tables.md#how-the-table-is-read) |
| `pos`    | `number`                          | The chart's or diagram's position. Defaults to the selected one                                    |

- **A key given as `undefined`** returns to the default.
- **A key left out** keeps its value.
- **A chart's label and series** stay on the same columns: on the column itself while it is
  still read, otherwise on the column at the same position, so they survive a new header.
- **The current values** are reported by `listCharts()` as `tableRead`, and by
  `listDiagrams()` as part of `link`.

Returns `false` for a chart or diagram that follows no table, whose table is gone, or, for a
diagram, when a column it names is no longer there.

### setChartLayout

Decides whether a chart's table is in the document with it.

```ts
editor.commands.setChartLayout({ layout: 'with-table' })
```

| Option   | Type                                 | Description                                          |
| -------- | ------------------------------------ | ---------------------------------------------------- |
| `layout` | `'chart' \| 'with-table' \| 'table'` | What the document holds, see below                   |
| `pos`    | `number`                             | The chart's position. Defaults to the selected chart |

| `layout`       | The document holds                                                                 |
| -------------- | ---------------------------------------------------------------------------------- |
| `'chart'`      | The chart alone, with its own data                                                 |
| `'with-table'` | The chart and a table it follows, wherever each stands                             |
| `'table'`      | The table alone; the chart stays directly below it, hidden, and keeps following it |

- **Where the chart and its table stand** is not part of the layout. Move either Node to move
  it.
- **`'with-table'` on a chart with its own data** inserts a table of that data directly above
  the chart, which the chart follows from then on, as with `insertLinkedChart`.
- **`'chart'`** keeps the data the table last gave and follows nothing. The table is removed,
  unless another chart or diagram still follows it.
- **`'table'`** moves the chart directly below its table if it stands elsewhere.
- **Title, Renderer and the rest of the spec** are kept, also while the chart is hidden, so any
  other layout shows it again as it was.
- **The change** is one undo step.
- **A hidden chart** is left out of `exportAll` and `exportDocx`, and in HTML its `<figure>`
  carries `hidden`.
- **Deleting or moving its table** shows the chart again.
- **To keep only a table and no chart**, use `convertChartToTable`.
- `listCharts()` reports the current layout as `layout`.

Returns `false` for `'with-table'` and `'table'` on a chart whose data comes from another
linked, read-only source, without the option `chart.linkTables`, and for `'table'` when
another hidden chart already stands below that table.

### linkChartToTable

Makes a chart follow a table anywhere in the document, not only beside it.

```ts
const [table] = editor.storage.diagrams.listTables()
if (table) editor.commands.linkChartToTable({ table: table.pos })
```

| Option     | Type                              | Description                                                                                     |
| ---------- | --------------------------------- | ----------------------------------------------------------------------------------------------- |
| `table`    | `number`                          | The table's position, as `listTables()` reports it                                              |
| `pos`      | `number`                          | The chart's position. Defaults to the selected chart                                            |
| `readOnly` | `boolean`                         | `false` keeps the chart's data editable while linked. Default `true`                            |
| `header`   | `'auto' \| 'first-row' \| 'none'` | As for [`insertLinkedChart`](https://tiptap.dev/docs/diagrams/data/tables.md#insertlinkedchart) |
| `range`    | `{ rows?, columns? }`             | As for [`insertLinkedChart`](https://tiptap.dev/docs/diagrams/data/tables.md#insertlinkedchart) |

- The table gets an id if it has none.
- The chart takes its data at once and follows every edit in the same Transaction.
- Such a chart reports `layout: 'chart'`, since the table is not its neighbor.
- Needs the option `chart.linkTables`.

Returns `false` for a position that holds no table and for a table that is an open input view.
