Skip to content

Nested Tables in Markdown: Put a Table Inside a Table

By MarkdownTables.com editorial teamUpdated

On this page

How do I put a table inside a table on GitHub?

GitHub allows raw HTML tables, and an HTML table cell can contain another HTML table. Write both tables with HTML tags and keep the inner one free of blank lines and Markdown:

A table inside a table cell (GitHub)HTML
<table>
  <tr>
    <th>Region</th>
    <th>Revenue by quarter</th>
  </tr>
  <tr>
    <td>Europe</td>
    <td>
      <table>
        <tr><th>Q1</th><th>Q2</th></tr>
        <tr><td>$1.2M</td><td>$1.4M</td></tr>
      </table>
    </td>
  </tr>
  <tr>
    <td>Asia</td>
    <td>
      <table>
        <tr><th>Q1</th><th>Q2</th></tr>
        <tr><td>$0.9M</td><td>$1.1M</td></tr>
      </table>
    </td>
  </tr>
</table>

This renders as an outer table with a Region column and, in each row, a small Q1/Q2 table. Three rules keep it working:

  • Use HTML inside the inner table. **bold** and backticks are not processed there, so use <b> and <code>.
  • Don't leave blank lines inside the table. A blank line ends the HTML block and the rest is read as Markdown again.
  • Don't count on styling. GitHub strips style attributes, so borders and widths come from its own stylesheet. The nested table is drawn with GitHub's default table look.

You don't have to write the outer table by hand. Build it as a pipe table, convert it with Markdown table to HTML, and paste the inner <table> into the cell. Plain HTML also keeps the nested table out of the way of the pipe rules in the next section.

Why a Markdown table can’t go inside a table

A GFM pipe table is parsed line by line. Every row is one line of text, split at each unescaped |, and each cell can hold only inline content: emphasis, code spans, links, images and inline HTML. A table is a block, and a block needs its own header line, delimiter line and rows. So the pipes of an inner table are read as more columns of the outer row.

The same limit keeps lists and fenced code blocks out of cells. The full rule set is in the Markdown table syntax guide.

Broken: the inner table’s pipes become extra columns
Markdown
| Region | Breakdown   |
| ------ | ----------- |
| Europe | | Q1 | Q2 |  |
|        | | -- | -- |  |
|        | | 1.2M | 1.4M | |
Preview
RegionBreakdownColumn 3Column 4Column 5
EuropeQ1Q2
----
1.2M1.4M

The outer table has two columns, so the extra cells are dropped and the inner rows are not a table.

Every way to show tables within tables

Ways to show a table within a table, and where they work
MethodHowWorks onTrade-off
HTML table in a <td><td><table>…</table></td>GitHub, GitLab, VS Code, Jupyter, MkDocs, JekyllReal nesting; HTML source, no Markdown inside
Pipe table in a pipe cell| a | | b | c | |NowhereThe inner pipes add columns
Flat table with a group columnRepeat the parent value on each rowEverywhere tables workSortable and diff-friendly
Blank repeated cellsLeave the group cell empty after the first rowEverywhere tables workReads as merged; loses meaning if sorted
Bold group rows| **Server** | | as a divider rowEverywhere tables workA fake row; screen readers read it as data
Subheadings, one table each### Group then a tableEverywhereBest readability; separate column widths
Summary table plus <details>Links to collapsible inner tablesGitHub, GitLabDetail stays hidden until opened
Merged cellsrowspan / colspan in HTMLGitHub, GitLab, most HTML-friendly renderersLooks nested without being a second table
Grid tableTable drawn inside a +---+ cellPandoc, QuartoTest nesting with your pandoc version

Flatten it: one table with a group column

Most “tables in tables” are really grouped data: each parent has several children. A flat table with a group column holds the same information in one grid, and it stays sortable, filterable and easy to diff.

One table with a Group column
Markdown
| Group    | Setting  | Default |
| :------- | :------- | :------ |
| Server   | `port`   | 8080    |
| Server   | `host`   | 0.0.0.0 |
| Database | `url`    | (none)  |
| Database | `pool`   | 10      |
Preview
GroupSettingDefault
Serverport8080
Serverhost0.0.0.0
Databaseurl(none)
Databasepool10

If repeating the group name is noisy, leave it empty after the first row. This looks like a merged cell, but every other row still shows an empty first cell to a screen reader, so use it only for small tables.

Group name only on the first row of each group
Markdown
| Group    | Setting  | Default |
| :------- | :------- | :------ |
| Server   | `port`   | 8080    |
|          | `host`   | 0.0.0.0 |
| Database | `url`    | (none)  |
|          | `pool`   | 10      |
Preview
GroupSettingDefault
Serverport8080
host0.0.0.0
Databaseurl(none)
pool10

A third pattern is a divider row: a bold group name with empty value cells. It reads well but is not real structure. For true spans, see merged cells.

Bold divider rows between groups
Markdown
| Setting  | Default |
| :------- | :------ |
| **Server** |       |
| `port`   | 8080    |
| `host`   | 0.0.0.0 |
| **Database** |     |
| `url`    | (none)  |
| `pool`   | 10      |

Split it: subheadings and one table per group

If the groups have different columns, or each group deserves its own heading in the page outline, write one table per group. Headings also give readers anchor links to each part.

One table per group under subheadingsMarkdown
### Server

| Setting | Default |
| :------ | :------ |
| `port`  | 8080    |
| `host`  | 0.0.0.0 |

### Database

| Setting | Default |
| :------ | :------ |
| `url`   | (none)  |
| `pool`  | 10      |

Use this when the inner and outer data answer different questions. The table editor is handy for building each small table.

Drill down: a summary table plus collapsible detail

For reference tables where the detail is long, keep an overview table and put each inner table in a <details> section below it. Point to it from the cell. A blank line after <summary> and before </details> lets the table render as Markdown. See collapsible tables.

Overview table that links to a collapsible detail tableMarkdown
| Endpoint     | Auth  | Details                  |
| :----------- | :---- | :----------------------- |
| `/users`     | Token | Fields for /users below  |
| `/orders`    | Token | Fields for /orders below |

<details>
<summary>Fields for /users</summary>

| Field | Type   |
| :---- | :----- |
| id    | number |
| email | string |

</details>

Pandoc: block content in grid-table cells

Pandoc grid tables draw cell borders with +, -, = and |, and the manual says a cell can contain any block-level element, including lists, code blocks and several paragraphs.

Block content in a Pandoc grid tableMarkdown
+--------+---------------------------+
| Region | Notes                     |
+========+===========================+
| Europe | - Q1 beat the plan        |
|        | - Q2 includes a one-off   |
|        |                           |
|        | See the *annual* report.  |
+--------+---------------------------+

That includes another table, in principle. Nested grid tables should work in recent pandoc 3 releases, but the manual doesn't spell it out and output varies by format, so treat the example below as something to test with your pandoc version rather than a guarantee.

A grid table inside a grid-table cell (test with your pandoc)Markdown
+--------+------------------+
| Region | Revenue          |
+========+==================+
| Europe | +------+-------+ |
|        | | Q1   | Q2    | |
|        | +======+=======+ |
|        | | 1.2M | 1.4M  | |
|        | +------+-------+ |
+--------+------------------+
| Asia   | Reported yearly  |
+--------+------------------+

Pandoc pipe tables nest no better than GFM ones. See the Pandoc tables guide.

Nested tables by platform

Nested tables by platform
PlatformPipe table in a pipe cellHTML table inside an HTML cellBlock content in a cell
GitHub (GFM)Pipe tables can’t nest. HTML <table> elements are allowed, including inside a <td>; style attributes are stripped.NoYesPartly: HTML table, blank lines around Markdown
GitLab (GLFM)Same pipe-table limit. HTML tables are allowed in Markdown.NoYesPartly: HTML table, blank lines around Markdown
VS Code previewThe built-in preview passes HTML tables through.NoYesPartly: HTML table, blank lines
ObsidianReading view renders HTML tables, but Obsidian sanitizes HTML, so check a nested table in Reading view.NoPartly: Reading view, check outputNo
JupyterMarkdown cells render sanitized HTML, including tables.NoYesNo
Pandoc / QuartoGrid-table cells hold any block content. Nested grid tables are accepted by recent pandoc 3 releases as far as the manual says; test with your version.NoPartly: HTML output onlyYes: Grid tables
MkDocs (Python-Markdown)Inline HTML passes through; md_in_html parses Markdown inside HTML cells.NoYesYes: md_in_html
Hugo (Goldmark)Raw HTML is dropped unless markup.goldmark.renderer.unsafe is true.NoPartly: Needs unsafe = truePartly: HTML table + unsafe
RedditNo inline HTML. Use a flat table or headings.NoNoNo

✅ supported · ⚠️ partly or with a workaround · ❌ not supported · Last verified October 2026

“Block content in a cell” means Markdown lists, code blocks or tables inside a cell. Where it says HTML table, write the whole table in HTML and leave blank lines around the Markdown.

Common mistakes (broken vs. fixed)

A pipe table in a pipe cell

Shown above: the inner pipes become columns. There is no escape that fixes it. Convert the outer table to HTML or flatten the data.

A blank line inside the HTML table

Broken: the blank line ends the HTML blockHTML
<table>
  <tr>
    <td>Europe</td>
    <td>
      <table>

        <tr><td>Q1</td><td>$1.2M</td></tr>
      </table>
    </td>
  </tr>
</table>

The blank line closes the HTML block, so the lines after it are parsed as Markdown, and the indented <tr> can become a code block. Remove blank lines inside HTML tables unless you mean to switch to Markdown.

Markdown syntax inside the inner table

Broken: shows literal asterisks and backticksHTML
<table>
  <tr>
    <td>Europe</td>
    <td>
      <table>
        <tr><th>Quarter</th><th>Revenue</th></tr>
        <tr><td>**Q1**</td><td>`$1.2M`</td></tr>
      </table>
    </td>
  </tr>
</table>
Fixed: HTML tags inside HTMLHTML
<table>
  <tr>
    <td>Europe</td>
    <td>
      <table>
        <tr><th>Quarter</th><th>Revenue</th></tr>
        <tr><td><b>Q1</b></td><td><code>$1.2M</code></td></tr>
      </table>
    </td>
  </tr>
</table>

Styling the nested table

<table style="border:1px solid"> is silently stripped on GitHub. Don't design the nested table around borders or colors; see Markdown table styling for what survives where.

When to restructure instead of nesting

Nesting is a sign the data has two levels. Before you reach for HTML, ask who reads the table:

  • Humans scanning a README. Use subheadings with one small table each, or a flat table with a group column.
  • People who need to sort or filter. Flatten it. Repeat the parent value on every row; the table sorter then works on the source.
  • Reference docs with long detail. Overview table plus collapsible sections.
  • A true spanning layout. Use rowspan/colspan via merged cells rather than a second table.
  • PDF or Word output. Use Pandoc grid tables, and test nested ones with your version.

To turn a finished pipe table into the HTML for the outer table, use the Markdown table to HTML converter.

Frequently asked questions

Can you nest a table inside a table in Markdown?

No, not with pipe-table syntax: a cell holds only one line of inline content, so a second pipe table just adds columns. Write the outer table in HTML and put a <table> inside a <td>, or restructure the data so no nesting is needed.

How do I make a nested table in a GitHub README?

Use an HTML <table> for the outer table and another <table> inside one of its <td> cells. GitHub renders it. Keep the inner table in HTML tags only, with no blank lines inside it, and don’t rely on style attributes because GitHub strips them.

Can I put a Markdown table inside an HTML table cell?

Yes on GitHub and GitLab, if a blank line separates the Markdown table from the surrounding <td> tags and the table is not indented four spaces. Then the cell content is parsed as Markdown again. Mixing the two is fragile, so plain HTML for the inner table is the safer choice.

Is there a Markdown flavor that supports nested tables?

Pandoc grid tables allow block-level content in cells, and the Pandoc manual describes a cell as containing any block elements. Nested grid tables should work in recent pandoc 3 releases, but check with your version and output format. Pipe tables never nest.

How do I show hierarchical data in a Markdown table?

Add a group column and repeat the parent value on each row, or leave the repeated cells empty after the first row. For longer hierarchies, use one table per group under subheadings, or a summary table that links to collapsible <details> sections.

Why does my nested Markdown table turn into extra columns?

Every | in a pipe-table row starts a new cell, so the inner table’s pipes are read as more columns of the outer row. GFM has no escape that turns them into a table, so move the inner data out or switch the outer table to HTML.

Can I merge cells instead of nesting tables?

Only with HTML (rowspan and colspan), MultiMarkdown’s || for column spans, or Pandoc grid tables. GFM pipe tables have no merged cells. See merged cells in Markdown tables for each option.