Table Alignment
The delimiter row of a table does two jobs. It says “everything below this line is data”, and it also decides how each column is aligned. The syntax for that second job is a single character: the colon. Put it on the left edge of a cell and the column leans left, put it on the right edge and the column leans right, put it on both edges and the column is centered, leave it out and the column keeps whatever the surrounding style says. The whole rule fits in one sentence: the colons live in the delimiter row and nowhere else.
Alignment is a property of the column, not of an individual cell. You declare it once, in the delimiter row, and it applies to the header cell and to every data cell in that column, so a table never mixes two alignments inside one column. This page also covers what the alignment actually changes — the content inside a cell, not the width of the column — why a theme can overrule it, and which platforms ignore the markers altogether.
Every HTML sample below was produced by running the source through a GitHub Flavored Markdown (GFM) parser, so the attributes you see are the ones a renderer really emits.
A delimiter cell holds hyphens, with an optional colon on either edge. The four combinations give you the four outcomes:
| Left | Center | Right |
| :--- | :---: | ---: |
| A | B | C |
<table>
<thead>
<tr>
<th align="left">Left</th>
<th align="center">Center</th>
<th align="right">Right</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">A</td>
<td align="center">B</td>
<td align="right">C</td>
</tr>
</tbody>
</table>
The colon on the left asks for left alignment, the colon on the right asks for right alignment, a colon on both sides asks for the center, and no colon at all means the column carries no alignment declaration and the theme decides.
No colon means no declaration
This is worth looking at closely, because “no alignment” and “left aligned” are not the same thing. A column without a colon gets no alignment attribute at all:
| Default | Left | Center | Right |
| --- | :-- | :-: | --: |
| A | B | C | D |
The first column has no alignment attribute on any of its cells, while the other three carry one — the second one asks for the left, the third for the center, the fourth for the right. The visual result is often still left alignment, because left is the usual default for text — but it is the theme’s default, not yours, and a theme is free to choose something else.
The number of hyphens does not matter
The hyphens in a delimiter cell exist to make the row recognizable as a delimiter row. They do not set a width and they do not have to line up with the header text. One hyphen is enough, and this table aligns exactly like the one above:
| Left | Center | Right |
| :- | :-: | -: |
| A | B | C |
Padding the cells so the dashes line up under the headings is still worth doing, because it keeps the source readable and makes it obvious which cell declares which alignment. That is a habit for the human eye, not a requirement of the parser.
Two colons in one cell break the table
A delimiter cell may carry at most one colon on each side. Two colons on the same edge make the row an invalid delimiter row, and the table is not recognized at all:
| a |
| ::--- |
| 1 |
<p>| a |
| ::--- |
| 1 |</p>
The failure is silent: the block comes out as three lines of text, and the reason — a colon that has been doubled — is easy to miss when you read the source.
Once the alignment has been declared for a column, the data rows do not repeat it. They do not need to, and they must not: a colon in a data row is an ordinary character, part of the cell’s text.
| a | b |
| --- | --- |
| x: | y |
The cell in the first column reads x: and nothing else. The same is true for a value such as https://example.com, which is full of colons and needs no escaping.
A colon in a data row is just a character, and a doubled colon in the delimiter row breaks the table. Both mistakes point at the same rule: the parser reads the alignment from the delimiter row only. Write | :--- | there and you have declared a left-aligned column; write | x: | in a data row and you have written the letter sequence x: into a cell; write | ::--- | and the row stops being a delimiter row, so the whole block degrades into plain text with no warning at all.
The alignment applies to the content inside each cell. It says which edge of the cell the text should hug, and it does not decide how wide the column is. Column width comes from the content and from the table layout algorithm: the widest cell sets the width, and the rest of the column is padded to match.
That is why right alignment is the useful choice for numbers. The width still follows from the longest value, but the digits line up on the right edge, so a reader can compare two amounts at a glance instead of counting characters. If two rows of prices are to line up on the decimal point, the alignment has to be right; no amount of padding in the source will achieve it.
In the generated HTML the alignment becomes an alignment attribute on every cell of the column, header cells included. Because that attribute is a presentational one, it behaves like a text alignment declaration: a stylesheet rule for the cells of the table overrides it. As long as the theme stays out of the way the colons do their job; the moment a theme sets its own text alignment for table cells, the theme wins and the colons in your source have no effect at all. That is one of the reasons the same Markdown file can look different on two different sites.
- Numbers, amounts, versions, and dates: right alignment, because the characters have the same width and the digits line up.
- Short labels and statuses such as “done” or “failed”: the center is fine and often looks tidier than the left edge.
- Prose and descriptions: keep them left aligned, since the lengths differ so much that centering makes the start of each line wander.
A table with three different alignments is usually a sign that the table carries three kinds of data, which is exactly the case where alignment helps. A table where every column is centered is usually a table where nobody thought about it.
Alignment is a hint, and different tools treat it differently. A renderer that does not implement the table extension at all — a plain CommonMark parser — has no columns to align, and the same source comes out as a paragraph, exactly as described on the previous page. Renderers that do implement tables but ignore the colon markers fall back to their own default, which is usually left alignment for everything.
Documentation generators often do not turn Markdown into HTML at all: they hand the source to a table component, and that component decides what to do with the alignment. Some keep it, some drop it, and some let the site theme overrule it. The spelling that keeps the outer bars in the delimiter row, |---:|:---:|---:|, is still valid GFM, because the outer bars are optional — but it is only a convention, not a second syntax, and it does not change what the colons mean.
The practical advice is the same for all of these: check the rendered result once, in the place the document will actually live, instead of assuming the colons survived.
| Written as | What actually happens | Why |
|---|---|---|
| A colon on the left of a delimiter cell | The column is aligned left | The colon marks the left edge |
| A colon on the right of a delimiter cell | The column is aligned right | The colon marks the right edge |
| Colons on both sides of a delimiter cell | The column is centered | Both edges are marked |
| No colon in a delimiter cell | No alignment attribute | The theme decides |
| Two colons in one delimiter cell | Not a table at all | A cell takes at most one colon on each side |
| A colon in a data row | An ordinary character | The alignment is read from the delimiter row only |
| One hyphen instead of three in a delimiter cell | The same alignment | The hyphens only mark the delimiter row |
Rewrite the block below as a Markdown table with three columns: amount, status, and description. The amount column is right aligned, the status column is centered, the description column is left aligned, and one of the descriptions is bold.
amount status description
128.00 settled the order has been settled
9.90 pending waiting for the payment callback
Approach:
The alignment of every column is declared in the delimiter row, and only there: a colon on the left gives left alignment, a colon on the right gives right alignment, and colons on both sides give the center. The data rows carry no colons at all. The only thing to watch is that the delimiter row has exactly as many cells as the header row — three columns means three cells.
Steps:
- Write the header row
| amount | status | description |with three cells. - Write the delimiter row
| ---: | :---: | :--- |: the amount cell has its colon on the right, the status cell has colons on both sides, and the description cell has its colon on the left. - Write the first data row: the amount
128.00, the statussettled, and the description as**the order has been settled**. - Write the second data row: the amount
9.90, the statuspending, and the descriptionwaiting for the payment callbackas ordinary text. - Check the result: the table has three columns, the amounts hug the right edge, the statuses sit in the middle, the descriptions hug the left edge, and the header row is aligned exactly like the data rows.
Answer:
| amount | status | description |
| ---: | :---: | :--- |
| 128.00 | settled | **the order has been settled** |
| 9.90 | pending | waiting for the payment callback |You should now be able to write the four alignment forms, explain why a column without a colon carries no alignment attribute at all rather than a default one, and say that the alignment is declared once per column in the delimiter row while the data rows stay free of colons. You should also be able to explain that the alignment moves the content inside a cell rather than setting the width of the column, that a theme’s stylesheet can overrule the attribute your colons produce, and that a doubled colon in the delimiter row is one of the reasons a table sometimes refuses to become a table at all.
