Markdown cheatsheet · Table of contents

A table of contents in markdown

A markdown TOC is just a list of links pointing at the anchors renderers generate from headings. You can hand-write one, or let a tool insert and update it.

How heading anchors work

Anchors aren't part of core markdown (the CommonMark spec doesn't define them), but GitHub, GitLab and most documentation tools add an id to every heading: the text lowercased, spaces turned into dashes, most punctuation dropped. ## Getting Started! becomes #getting-started. When two headings produce the same slug, the second gets a -1 suffix, the third -2, and so on.

A manual TOC

List the sections you want and link each one to its slug. Nothing updates itself: rename a heading and you must fix the link by hand.

You type
## Contents

- [Install](#install)
- [Usage](#usage)

## Install
You get
Contents
Install
Navigating your own notes? In maxdown, Cmd+P opens a quick-open and full-text search palette, which is usually faster than maintaining a TOC. Save the TOC for documents other people will read.

GitHub generates one for you

On any rendered markdown file with two or more headings, GitHub shows an automatic outline: click the small list icon in the file header (it also appears on the README of a repository page). It covers all six heading levels and never goes stale, so most READMEs don't need an inline TOC anymore. A hand-written list still helps in very long documents, or when the file will be read outside GitHub.

Tools that insert one

In VS Code, the Markdown All in One extension has a Create Table of Contents command that inserts the list and keeps it updated on save; a slugifyMode setting matches GitHub or GitLab anchor rules. On the command line, doctoc (npx doctoc README.md) inserts a TOC block between HTML comment markers and updates it in place on every re-run, with GitHub-compatible anchors.

Some renderers also expand a token where the TOC should appear. [TOC] works in Typora and in Python-Markdown's toc extension. [[_TOC_]] works in GitLab (files, wikis, issues and merge requests; GitLab accepts [TOC] too) and in Azure DevOps wikis, where it is case-sensitive. Anywhere else these tokens render as literal text; GitHub, for example, just prints [TOC].

Common questions

Why does my anchor link not work?

The slug is stricter than the heading: punctuation and emoji are dropped, and a dropped character can leave a double dash behind. Duplicate headings are another trap; the second ## Setup needs #setup-1. The reliable fix is to copy the anchor from the rendered page: on GitHub, hover the heading, click the link icon that appears, and take the fragment from the URL. More in the links guide.

Related syntax

· All markdown guides

Less syntax. More writing.

Download maxdown

Free · no account · macOS, Windows & Linux