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:
<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
styleattributes, 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.
| Region | Breakdown |
| ------ | ----------- |
| Europe | | Q1 | Q2 | |
| | | -- | -- | |
| | | 1.2M | 1.4M | || Region | Breakdown | Column 3 | Column 4 | Column 5 |
|---|---|---|---|---|
| Europe | Q1 | Q2 | ||
| -- | -- | |||
| 1.2M | 1.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
| Method | How | Works on | Trade-off |
|---|---|---|---|
HTML table in a <td> | <td><table>…</table></td> | GitHub, GitLab, VS Code, Jupyter, MkDocs, Jekyll | Real nesting; HTML source, no Markdown inside |
| Pipe table in a pipe cell | | a | | b | c | | | Nowhere | The inner pipes add columns |
| Flat table with a group column | Repeat the parent value on each row | Everywhere tables work | Sortable and diff-friendly |
| Blank repeated cells | Leave the group cell empty after the first row | Everywhere tables work | Reads as merged; loses meaning if sorted |
| Bold group rows | | **Server** | | as a divider row | Everywhere tables work | A fake row; screen readers read it as data |
| Subheadings, one table each | ### Group then a table | Everywhere | Best readability; separate column widths |
Summary table plus <details> | Links to collapsible inner tables | GitHub, GitLab | Detail stays hidden until opened |
| Merged cells | rowspan / colspan in HTML | GitHub, GitLab, most HTML-friendly renderers | Looks nested without being a second table |
| Grid table | Table drawn inside a +---+ cell | Pandoc, Quarto | Test 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.
| Group | Setting | Default |
| :------- | :------- | :------ |
| Server | `port` | 8080 |
| Server | `host` | 0.0.0.0 |
| Database | `url` | (none) |
| Database | `pool` | 10 || Group | Setting | Default |
|---|---|---|
| Server | port | 8080 |
| Server | host | 0.0.0.0 |
| Database | url | (none) |
| Database | pool | 10 |
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 | Setting | Default |
| :------- | :------- | :------ |
| Server | `port` | 8080 |
| | `host` | 0.0.0.0 |
| Database | `url` | (none) |
| | `pool` | 10 || Group | Setting | Default |
|---|---|---|
| Server | port | 8080 |
host | 0.0.0.0 | |
| Database | url | (none) |
pool | 10 |
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.
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.
### 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.
| 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.
+--------+---------------------------+
| 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.
+--------+------------------+
| 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
| Platform | Pipe table in a pipe cell | HTML table inside an HTML cell | Block content in a cell |
|---|---|---|---|
GitHub (GFM)Pipe tables can’t nest. HTML <table> elements are allowed, including inside a <td>; style attributes are stripped. | No | Yes | Partly: HTML table, blank lines around Markdown |
| GitLab (GLFM)Same pipe-table limit. HTML tables are allowed in Markdown. | No | Yes | Partly: HTML table, blank lines around Markdown |
| VS Code previewThe built-in preview passes HTML tables through. | No | Yes | Partly: HTML table, blank lines |
| ObsidianReading view renders HTML tables, but Obsidian sanitizes HTML, so check a nested table in Reading view. | No | Partly: Reading view, check output | No |
| JupyterMarkdown cells render sanitized HTML, including tables. | No | Yes | No |
| 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. | No | Partly: HTML output only | Yes: Grid tables |
MkDocs (Python-Markdown)Inline HTML passes through; md_in_html parses Markdown inside HTML cells. | No | Yes | Yes: md_in_html |
Hugo (Goldmark)Raw HTML is dropped unless markup.goldmark.renderer.unsafe is true. | No | Partly: Needs unsafe = true | Partly: HTML table + unsafe |
| RedditNo inline HTML. Use a flat table or headings. | No | No | No |
✅ 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
<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
<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><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/colspanvia 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.