---
title: "Tables"
canonical_url: "https://www.nutrient.io/guides/document-authoring/editing-content/tables/"
md_url: "https://www.nutrient.io/guides/document-authoring/editing-content/tables.md"
last_updated: "2026-07-08T00:00:00.000Z"
description: "Build, read, and update tables in Document Authoring by adding tables, filling rows and cells, reading cell contents, and adding or removing rows and columns."
---

# Work with tables

A table is block-level content, like a paragraph. Inside a [transaction](https://www.nutrient.io/guides/document-authoring/editing-content/programmatic-editing.md), use [`addTable()`](https://www.nutrient.io/api/document-authoring/types/programmatic/blocklevelcontainer/#addtable) to add a table and build it from rows and cells.

Each table cell contains block-level content, so cell text lives in a paragraph inside the cell.

Before you start, make sure the Document Authoring library is installed and running in your app. If you haven’t set it up yet, refer to the [getting started](https://www.nutrient.io/sdk/document-authoring/getting-started.md) guide.

The examples omit error handling. Add it before you use this code in production.

## Understand new table content

Before you build a table, note these behaviors:

- A new table from [`addTable()`](https://www.nutrient.io/api/document-authoring/types/programmatic/blocklevelcontainer/#addtable) starts with one empty cell.

- Every row and cell you add already contains one empty paragraph.

- [`addRow()`](https://www.nutrient.io/api/document-authoring/types/programmatic/table/#addrow) sizes the new row to the table’s current column count, so appended rows already have the right number of cells.

Set a cell’s text on its existing paragraph instead of adding a new one. This helper does that and is reused throughout this guide:

```js

function setCellText(cell, text) {
  const [block] = cell.blocklevels(); // A cell always starts with one paragraph.
  if (block && block.type === 'paragraph') {
    block.asTextView().setText(text);
  }
}

```

## Build a table

A new table already contains one empty row. Remove that row first, and then add one row for each record. Pad each row’s cells up to the column count while the first row establishes the width. Then set each cell’s text:

```js

const currentDoc = editor.currentDocument();

await currentDoc.transaction(async ({ draft }) => {
  const table = draft.body().content().addTable();
  table.removeRow(0); // Remove the empty row the new table came with.

  const data = [
    ['Region', 'Revenue'],
    ['EMEA', '1.2M'],
    ['APAC', '0.8M'],
  ];

  for (const rowValues of data) {
    const row = table.addRow();
    while (row.cells().length < rowValues.length) {
      row.addCell();
    }
    rowValues.forEach((value, column) => setCellText(row.cells()[column], value));
  }

  return true;
});

```

## Read a table

Find tables in the block-level content by checking their `type`. Then walk through [`rows()`](https://www.nutrient.io/api/document-authoring/types/programmatic/table/#rows) and [`cells()`](https://www.nutrient.io/api/document-authoring/types/programmatic/tablerow/#cells). A cell’s text is in its first paragraph:

```js

await currentDoc.transaction(async ({ draft }) => {
  for (const blockLevel of draft.body().content().blocklevels()) {
    if (blockLevel.type!== 'table') continue;

    for (const row of blockLevel.rows()) {
      const values = row.cells().map((cell) => {
        const [firstBlock] = cell.blocklevels();
        return firstBlock?.type === 'paragraph'? firstBlock.asTextView().getPlainText()
          : '';
      });

      console.log(values.join(' | '));
    }
  }

  return false;
});

```

## Add and remove rows

Use [`addRow()`](https://www.nutrient.io/api/document-authoring/types/programmatic/table/#addrow) to append a row sized to the table’s columns. Then set text on the row’s existing cells. Use [`removeRow()`](https://www.nutrient.io/api/document-authoring/types/programmatic/table/#removerow) to remove the row at an index:

```js

await currentDoc.transaction(async ({ draft }) => {
  for (const blockLevel of draft.body().content().blocklevels()) {
    if (blockLevel.type!== 'table') continue;

    const row = blockLevel.addRow();
    setCellText(row.cells()[0], 'LATAM');
    setCellText(row.cells()[1], '0.3M');

    blockLevel.removeRow(0); // Remove the first row.

    break;
  }

  return true;
});

```

## Add and remove columns

A table doesn’t have a column object. A column is the cell at the same position in each row.

To add a column, add a cell to every row. Each new cell includes an empty paragraph. To remove a column, call [`removeCell()`](https://www.nutrient.io/api/document-authoring/types/programmatic/tablerow/#removecell) at the same index on every row:

```js

await currentDoc.transaction(async ({ draft }) => {
  for (const blockLevel of draft.body().content().blocklevels()) {
    if (blockLevel.type!== 'table') continue;

    for (const row of blockLevel.rows()) {
      setCellText(row.addCell(), '—');
    }

    break;
  }

  return true;
});

```

## Learn more

**[Text and formatting](https://www.nutrient.io/guides/document-authoring/editing-content/text-and-formatting.md)**\
Format text inside cells.

**[Programmatic editing](https://www.nutrient.io/guides/document-authoring/editing-content/programmatic-editing.md)**\
Learn how transactions work and how to use the document model.
---

## Related pages

- [Use copy/paste and HTML interoperability](/guides/document-authoring/editing-content/copy-paste-and-html-interoperability.md)
- [Work with lists](/guides/document-authoring/editing-content/lists.md)
- [Find and replace text](/guides/document-authoring/editing-content/find-and-replace.md)
- [Work with footnotes and endnotes](/guides/document-authoring/editing-content/footnotes-and-endnotes.md)
- [Edit documents programmatically](/guides/document-authoring/editing-content/programmatic-editing.md)
- [Work with images and shapes](/guides/document-authoring/editing-content/images-and-shapes.md)
- [Format text](/guides/document-authoring/editing-content/text-and-formatting.md)

