# Tables and Quotes

Course: [Markdown](https://www.devtutorials.ai/learn/markdown) · Section: Markdown Fundamentals
Source: https://www.devtutorials.ai/learn/markdown/fundamentals/tables-and-quotes

> Build tables that render where you need them. See why a table breaks outside GitHub and loses cells, align columns, escape pipes, decide when a list beats a table, and write quotes, dividers and strikethrough.

## The Table That Lost a Column

Ravi adds a table of support plans to the order-support docs. It looks right on GitHub. Then the same file goes to a docs site, and the table is gone.

```md runnable title="A table that only works in one place"
| Plan | Reply time | Price |
|---|---|---|
| Basic | 2 days | Free |
| Pro | 4 hours | ₹999 |
| Team | 1 hour | ₹2,999 | per month |
```

Look at the Rendered tab: a neat table. Now press **CommonMark** at the top of the box. The table turns into one paragraph of text full of pipes.

There is a second problem. Switch back to **GitHub (GFM)** and look at the last row. The words "per month" are gone. The row had one cell more than the header, and the extra cell was dropped without a word.

In this lesson, you will learn how tables work, where they break, and when a list or a quote does the job better.

**In simple words:** a table is a GitHub feature, not a CommonMark one. Every row must have the same number of cells as the header.

## TL;DR

- A **table** is rows of cells split by pipes `|`. The first row is the **header**. The second row is a **divider** of dashes.
- Colons in the divider set the **alignment**: `:---` left, `:---:` centre, `---:` right.
- Tables are part of **GitHub Flavored Markdown**. Plain CommonMark shows them as text.
- Every row needs the same number of cells as the header. Extra cells are dropped.
- To put a pipe inside a cell, write `\|`.
- A **blockquote** starts each line with `>`. It is for quoted text and notes.
- A line of three dashes `---`, with a blank line above it, draws a **divider line**.

## A Real-World Example

Think about a train timetable.

Each column is one thing: the train, the time, the platform. Each row is one train. You run your finger down a column to compare times. You run along a row to see everything about one train.

A table is for exactly this: comparing a few items on the same few points. But imagine writing a whole paragraph inside one timetable cell. It would not fit. Long text does not belong in a table.

## What You Will Learn

In this lesson, you will learn:

1. How to build a table with a header and a divider row.
2. How to align the columns.
3. Why tables break outside GitHub, and why cells go missing.
4. How to put a pipe inside a cell.
5. When a list is better than a table.
6. How to write blockquotes and divider lines.

## Cheat Sheet

```md runnable title="Tables, quotes and dividers"
| Plan | Reply time | Price |
|:-----|:----------:|------:|
| Basic | 2 days | Free |
| Pro | 4 hours | ₹999 |

> Refunds over ₹5,000 need a manager's approval.

---

~~Old rule~~ New rule
```

Change the cells, the colons and the `>` marks. Then switch between **CommonMark** and **GitHub (GFM)** and watch what changes.

## Building a Table

### Header, Divider, Rows

A **table** has three parts.

1. The **header row**: the column names, split by pipes `|`.
2. The **divider row**: a row of dashes, one group per column. It tells Markdown "the row above is a header".
3. The **body rows**: one row per item.

```md runnable title="A three-part table"
| Plan | Reply time |
|---|---|
| Basic | 2 days |
| Pro | 4 hours |
```

Open the HTML tab. The header row became `th` cells inside `thead`. The body rows became `td` cells inside `tbody`. `th` is a header cell and `td` is a normal cell.

Delete the divider row. The table disappears, because there is no table without a divider.

### The Pipes Do Not Need to Line Up

The pipes on each row do not need to line up with the rows above. The pipes at the start and end of each row are optional too. These two tables give the same result:

```md runnable title="Tidy or not, the same table"
| Plan  | Reply time |
|-------|------------|
| Basic | 2 days     |
| Pro   | 4 hours    |

Plan | Reply time
---|---
Basic | 2 days
Pro | 4 hours
```

Lined-up pipes are easier for people to read in the raw text. Many editors line them up for you. But keep the outer pipes: they make each row clearly a table row.

### Alignment

A colon in the divider row sets the **alignment** of a column.

| Divider | Alignment | Good for |
|---|---|---|
| `---` or `:---` | left | words |
| `:---:` | centre | short labels, ticks |
| `---:` | right | numbers and prices |

```md runnable title="Aligned columns"
| Plan | Included | Price |
|:---|:---:|---:|
| Basic | ✓ | Free |
| Pro | ✓ | ₹999 |
| Team | ✓ | ₹2,999 |
```

The prices line up on the right, so the digits sit under each other. Open the HTML tab: each cell got an `align` setting from the colons.

Right-align numbers only. Words that are right-aligned are hard to read, because each line starts in a different place.

## Where Tables Break

### Tables Are a GitHub Feature

Tables are not part of **CommonMark**, the core of Markdown. They come from **GitHub Flavored Markdown**, or **GFM**. Most places support GFM tables today: GitHub, GitLab, VS Code and most docs sites. But a strict CommonMark renderer does not.

Switch the last box to **CommonMark**. The table becomes one paragraph. If your file will be read by a tool you do not know, a list is the safer choice. You will learn more about the different flavours of Markdown in a later lesson.

A table is also harder for an AI agent than it looks. In the raw text, the agent has to count pipes to know which column a cell is in. A small table is fine. A wide table with long cells is easy to misread.

### Every Row Needs the Same Cells

The header sets the number of columns. Each body row should have exactly that many cells.

```md runnable title="Too many and too few cells"
| Plan | Reply time |
|---|---|
| Basic | 2 days | email only |
| Pro |
```

The Basic row has three cells, but the header has two. The third cell, "email only", was dropped. The Pro row has one cell, so the renderer added an empty one. Neither shows an error.

A dropped cell is easy to miss. After you change a table, count the cells in the header, and check that every row has the same number.

### A Pipe Inside a Cell

A pipe splits cells. So what if a cell needs a real pipe, such as a search pattern or a command? Write a backslash in front of it: `\|`.

```md runnable title="A pipe inside a cell"
| Pattern | Matches |
|---|---|
| `cat|dog` | broken |
| `cat\|dog` | cat or dog |
```

In the first row, the pipe split the code into two cells, and the backticks no longer match, so they show as text. The word "broken" became a third cell, and it was dropped. In the second row, `\|` kept the pipe inside the cell. This works inside inline code too.

A cell cannot hold more than one line. A line break ends the row. For a list or a long note inside a cell, use `<br>`, or better, move the content out of the table.

## When a List Beats a Table

Tables are good for comparing a few items on a few short points. They are bad for long text.

```md runnable title="A table that should be a list"
| Rule | Details |
|---|---|
| Refund window | Refunds are allowed within 30 days of delivery. After 30 days, offer a voucher instead, unless the item arrived damaged. |
| Damaged items | Ask for a photo first. Then refund in full, including shipping. |

## Refund window

Refunds are allowed within 30 days of delivery. After 30 days, offer a voucher instead, unless the item arrived damaged.

## Damaged items

Ask for a photo first. Then refund in full, including shipping.
```

The table squeezes long sentences into narrow cells. The second version uses headings and paragraphs. It is easier to read, and it shows up in the Outline tab, where an agent can find each rule by name.

| Use a table when | Use headings or a list when |
|---|---|
| every item has the same few properties | items have different kinds of detail |
| each cell is a word, a number or a short phrase | the text is a sentence or longer |
| readers compare across rows | readers read one item at a time |

## Blockquotes

### Quoting Text

A **blockquote** shows quoted text, set apart from the rest of the page. Start the line with `>` and a space.

```md runnable title="Blockquotes"
A customer wrote:

> The parcel arrived open.
> Two items were missing.

> One quote.
>
> A second paragraph in the same quote.

> A quote
>> inside a quote
```

Each `>` line joins the same quote. A line with only `>` makes a new paragraph inside the quote. Two `>` marks put a quote inside a quote, which is common in email replies.

Open the HTML tab. A blockquote becomes a `blockquote` tag.

### Notes and Alerts

People also use blockquotes for notes and warnings. GitHub has a special form called an **alert**:

```md title="A GitHub alert"
> [!WARNING]
> Refunds over ₹5,000 need a manager's approval.
```

On GitHub, this shows as a coloured box with a warning icon. Other renderers, and the boxes in this course, show it as a normal quote with `[!WARNING]` as text. It is a GitHub extension, not part of GFM tables or CommonMark. Use it in GitHub files, and know that it falls back to a plain quote elsewhere.

## Divider Lines

A **divider line**, also called a horizontal rule, draws a line across the page. Write three or more dashes, stars or underscores on a line by themselves.

```md runnable title="Three dividers"
Refund rules end here.

---

Shipping rules start here.

***

___
```

Open the HTML tab: each one is an `hr` tag.

Remember the trap from the Headings lesson: `---` right under a line of text turns that text into a heading. Always leave a blank line above a divider.

Use dividers rarely. A new heading usually separates sections better, and it also adds the section to the outline.

## Strikethrough

GFM also adds **strikethrough**: a line through text, to show it is no longer true. Wrap the text in two tildes.

```md runnable title="Strikethrough"
Reply time: ~~3 days~~ 2 days.
```

Switch to **CommonMark**: the tildes show as text. Like tables, strikethrough is a GFM feature.

## Where This Is Used

- **README files:** a table of supported versions, or of commands and what they do.
- **Docs sites:** comparison tables of plans, options and settings.
- **Specs:** a table of inputs and expected outputs.
- **Release notes:** strikethrough for a fixed known issue.
- **Issues and emails:** blockquotes for the customer's exact words.

## Common mistakes

| Symptom | Cause | Fix |
|---|---|---|
| The table shows as text full of pipes | No divider row, or the renderer does not support GFM | Add the `---` row; for strict CommonMark tools, use a list |
| A cell is missing from the page | The row has more cells than the header | Make every row match the header |
| A cell is split in two | A `\|` inside the cell | Write `\\|` |
| A row ends early, and the rest becomes a new paragraph | A line break inside a cell | Keep each row on one line; use `<br>` for a break |
| A table is hard to read | Long sentences in narrow cells | Turn it into headings and paragraphs, or a list |
| `[!WARNING]` shows as text | The renderer does not support GitHub alerts | Fine as a fallback; or write "**Warning:**" in the quote |
| `~~text~~` shows the tildes | Strikethrough is GFM-only | Use a GFM renderer, or write "was:" in words |

## Quick Check

## Exercises

## What to Remember

- A table is a header row, a divider row of dashes, and body rows, split by pipes.
- Colons in the divider set alignment. Right-align numbers with `---:`.
- Tables are GitHub Flavored Markdown. Strict CommonMark shows them as text.
- Every row needs the same number of cells as the header. Extra cells vanish without a warning.
- Write `\|` for a pipe inside a cell. Keep cells short and on one line.
- Use headings or lists for long content. Use `>` for quotes, and `---` with a blank line above for a divider.

## Further Reading

- [GitHub Flavored Markdown: tables](https://github.github.com/gfm/#tables-extension-): the exact table rules.
- [CommonMark: block quotes](https://spec.commonmark.org/0.31.2/#block-quotes): how `>` works.
- [GitHub Docs: alerts](https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax#alerts): note and warning boxes on GitHub.

Next: **Escaping and HTML**, where you stop Markdown from changing text you meant literally, and test yourself with a predict-the-render quiz.
