GFM pipe tables: alignment, separators, and sorting rows
Published: 2026-09-05
How GitHub-flavored Markdown pipe tables work—header and separator rows, left/center/right colon markers, column padding, and sorting body rows by column without uploading your draft.
GitHub Flavored Markdown (GFM) pipe tables are the tables you see in READMEs, pull requests, and many docs sites: rows of cells separated by |, plus a separator row of dashes that tells renderers “this is a table” and optionally how each column should align.
They are easy to write badly by hand. One short cell next to a long header makes pipes zigzag; a missing separator breaks rendering; sorting by score in a spreadsheet and pasting back often destroys alignment. A local formatter can pad columns and reorder body rows while keeping prose outside the table untouched.
LocalTools’ Markdown table formatter finds contiguous pipe-table blocks in your paste, aligns columns, preserves separator alignment markers, and can sort data rows by a chosen column—entirely in the browser.
Anatomy of a GFM pipe table
A minimal table needs at least two consecutive lines that contain |. The usual shape is:
- Header row — column titles.
- Separator row — only dashes (and optional
:alignment markers) between pipes. - Body rows — one or more data rows.
| Name | Score |
| --- | ---: |
| Ada | 95 |
| Bob | 8 |
| Part | Role |
|---|---|
| Header | Labels for columns; usually not sorted away |
| Separator | Required for GFM table recognition; encodes alignment |
| Body | Data rows; safe to reorder when sorting |
Leading and trailing pipes on each line are conventional (| a | b |) but some editors omit them. Formatters typically normalize to a consistent pipe style within a block.
Separator alignment markers
GFM uses colons on the separator cells to set column alignment in HTML output (text-align):
| Separator cell | Alignment |
|---|---|
--- or :--- |
Left (default) |
---: |
Right |
:---: |
Center |
Example:
| Left | Center | Right |
| :--- | :---: | ---: |
| a | b | c |
When you align or reformat, keep the colon pattern for each column. Changing :---: to --- silently left-aligns that column in GitHub’s renderer even if the cells still look centered in a monospace editor.
A formatter pads cell text with spaces so pipes line up in the source. Widths are based on visible character counts in the cells; wide emoji or combining marks can still look uneven in some fonts even when the source is padded correctly.
What counts as a table block
In mixed documents (a README with prose and several tables), contiguous lines that contain | form a block. Blank lines and non-pipe lines break the block. Formatting should:
- Rewrite each block into aligned rows.
- Leave surrounding Markdown (headings, lists, code fences) unchanged.
- Preserve a trailing newline on the whole paste when one was present.
A single pipe-containing line is not enough—GFM needs the header/separator pattern (or at least two pipe rows for a naive aligner). If you paste a half-table, fix the structure first.
Sorting body rows (not the header)
Sorting a markdown table is almost always about data rows under the separator. The header and separator stay fixed; only body rows reorder.
| Option | Effect |
|---|---|
| No sort | Align / pad only; row order unchanged |
| Sort by column | Reorder body rows using that column’s cell text |
| Ascending / descending | Direction of the comparison |
| Lexicographic vs numeric digits | Lexicographic puts 10 before 2; numeric puts 2 before 10 |
Comparison is typically locale-aware and case-insensitive at the base letter level (Ada and ada group together). That matches how people expect name and label columns to sort—similar to sorting lines outside a table.
Tables without a separator row are awkward in strict GFM, but a practical tool may treat the first row as the header and everything after as body when you ask to sort. Prefer adding a real | --- | separator so GitHub and other renderers agree.
Practical workflow
- Paste a full table or a README fragment that includes one or more pipe tables.
- Confirm separator colons match the alignment you want (right-align numbers with
---:). - Choose align only, or pick a sort column and direction (numeric digit order for scores, versions, and IDs).
- Copy the formatted output back into the file.
- If you reformatted both sides of a change, diff them so the review is about content, not pipe drift—see text diffs.
For HTML snippets elsewhere in the same doc, a separate HTML formatter is the right tool; pipe tables stay Markdown until a renderer turns them into <table>.
Common pitfalls
- Missing separator — Many renderers show the pipes as ordinary paragraph text instead of a table.
- Uneven column counts — A short row is often padded with empty cells; check that you did not drop a
|mid-row. - Sorting the wrong column — Header labels stay put; verify you sorted by Score, not Name.
- Lexicographic numbers — Without numeric ordering,
95can sort “before”8incorrectly for humans. - Pipes inside cells — Literal
|in cell text breaks naive splitting unless escaped or avoided; prefer rephrasing or HTML entities in edge cases. - Uploading drafts — README tables sometimes include internal codenames or metrics. Prefer a local-only pass.
Try it locally
Open the Markdown table formatter:
- Paste a GFM pipe table (or prose that embeds one).
- Leave sort off to align only, or choose a column, direction, and digit ordering.
- Copy the formatted output. Processing stays in your tab; nothing is uploaded.
Related reading
- Markdown table formatter — align pipes and sort columns locally
- Sorting and deduping lines — locale and numeric ordering for flat lists
- Text diffs: unified view and workflow
- Formatting HTML snippets in the browser
- Why “local only” matters for developer tools
- Diff Checker — compare before/after after formatting both sides