Markdown Headings

How to create headings in Markdown — from H1 to H6, with examples and SEO tips

Heading Syntax

Markdown uses hash symbols (#) to create headings. The number of hashes determines the heading level — one hash for H1, two for H2, up to six for H6. Always put a space between the hash symbols and the heading text.

Heading Level 1
# Heading Level 1
Heading Level 2
## Heading Level 2
Heading Level 3
### Heading Level 3
Heading Level 4
#### Heading Level 4
Heading Level 5
##### Heading Level 5
Heading Level 6
###### Heading Level 6

This syntax is called ATX-style headings, after the text formatting system that introduced it. It is the standard heading syntax in CommonMark and GitHub Flavored Markdown.

Alternative Syntax (Setext Headings)

Markdown also supports an older heading style called Setext headings. Instead of hash symbols, you underline the heading text with equal signs for H1 or hyphens for H2.

Heading Level 1
Heading Level 1
===============
Heading Level 2
Heading Level 2
---------------

Setext headings only support H1 and H2 — there is no underline syntax for H3 through H6. For this reason, ATX-style headings (#) are preferred in modern Markdown. They are more flexible, more consistent, and easier to scan in source files.

The number of = or - characters does not matter, as long as there is at least one. Most authors use three or more for readability.

Heading IDs and Anchor Links

Most Markdown processors automatically generate an id attribute for each heading, based on the heading text. This lets you create links that jump directly to a specific section of a page.

Auto-generated IDs

The ID is created by converting the heading text to lowercase, replacing spaces with hyphens, and removing special characters. For example:

HeadingGenerated ID
## Getting Started#getting-started
## What's New?#whats-new
## Step 1: Install#step-1-install

Linking to a heading

Use the auto-generated ID in a standard Markdown link to jump to that section:

See the [Getting Started](#getting-started) section.

Link to another file's heading:
[Install guide](setup.md#installation)

Custom heading IDs

Some Markdown processors (including Kramdown and Pandoc) let you set a custom ID with curly braces:

## Long Heading Text That Would Make an Ugly ID {#short-id}

Note: GitHub Flavored Markdown does not support custom heading IDs. This feature is processor-specific.

Table of Contents

Headings define the structure of a Markdown document, and many tools use that structure to generate a table of contents (TOC) automatically.

Manual TOC

You can build a table of contents by hand using anchor links to each heading:

Table of Contents

  1. Installation
  2. Configuration
  3. Usage
## Table of Contents
1. [Installation](#installation)
2. [Configuration](#configuration)
3. [Usage](#usage)

Automatic TOC generation

Many Markdown tools generate a TOC from your headings automatically:

  • GitHub: Shows a TOC button on files with two or more headings
  • GitLab: Use [[_TOC_]] to insert a generated table of contents
  • VS Code: The Outline panel lists all headings in the current file
  • Obsidian: Use the [[toc]] syntax or an outline plugin
  • MDViewer: Generates a clickable sidebar outline from your headings

Heading Best Practices

Following heading conventions improves readability, accessibility, and SEO for your Markdown documents.

Use one H1 per document

The H1 heading represents the document title. Using more than one H1 weakens the document hierarchy and confuses both readers and search engines. Use H2 for major sections beneath the title.

Maintain logical hierarchy

Headings should form a clean outline. An H3 should always appear under an H2, never directly under an H1. Think of it like a nested list — each sub-level should be one step deeper, not two.

# Project Name          (H1 — document title)
## Installation         (H2 — major section)
### Prerequisites       (H3 — subsection)
### Steps               (H3 — subsection)
## Usage                (H2 — major section)
### Basic Commands      (H3 — subsection)
### Advanced Options    (H3 — subsection)

Do not skip heading levels

Jumping from H2 to H4 breaks the document outline. Screen readers and SEO crawlers expect headings to descend in order. If a section does not need a deep heading, keep it at the appropriate level.

Keep headings concise

Short headings are easier to scan and they create cleaner anchor links. Aim for 3–8 words. Avoid putting full sentences or questions longer than 10 words in a heading.

Add a blank line around headings

While not always required by the parser, putting a blank line before and after each heading improves readability in the source file and prevents parsing ambiguity in some processors.

Headings in GitHub README

GitHub renders Markdown headings with automatic anchor links. Hovering over a heading in a rendered file reveals a link icon you can click to copy a direct URL to that section.

Anchor link format

GitHub generates heading IDs by converting text to lowercase, replacing spaces with hyphens, and stripping special characters. Duplicate headings get a numeric suffix (-1, -2, etc.).

HeadingGitHub anchor
## Quick Start#quick-start
## FAQ (first)#faq
## FAQ (second)#faq-1

Collapsible sections below headings

GitHub supports the <details> HTML element for collapsible content. This is useful for long sections like changelogs, FAQs, or advanced configuration:

## Changelog

<details>
<summary>v2.0.0 (2026-10-01)</summary>

- Added dark mode
- Fixed export bug
- Updated dependencies

</details>

The Markdown inside <details> renders normally when expanded. Leave a blank line after <summary> for Markdown parsing to work correctly.

Platform Support

Markdown headings are part of the original Markdown specification. All six ATX-style levels (# through ######) work on every major platform. Setext headings and heading IDs vary by processor.

Feature GitHub GitLab VS Code Obsidian MDViewer
ATX headings (#) Yes Yes Yes Yes Yes
Setext headings (===) Yes Yes Yes Yes Yes
Auto-generated IDs Yes Yes Extension Yes Yes
Custom IDs ({#id}) No No Extension Yes No
TOC generation Built-in [[_TOC_]] Outline Plugin Built-in
Anchor link on hover Yes Yes No No Yes

Common Mistakes

No space after the hash symbol

Forgetting the space between # and the heading text causes most processors to render the line as a paragraph with literal hash characters instead of a heading.

MarkdownResult
# HeadingRenders as heading
#HeadingRenders as plain text in most processors
# Heading     <-- correct: space after #
#Heading      <-- broken: no space

Skipping heading levels

Jumping from H2 to H4 or from H1 to H3 creates gaps in the document outline. This confuses screen readers, breaks accessibility, and can hurt SEO rankings.

## Section            <-- H2
#### Subsection       <-- H4 (wrong: skipped H3)

## Section            <-- H2
### Subsection        <-- H3 (correct)

Using multiple H1 headings

A document should have exactly one H1. Multiple H1 headings make the page look like it has several unrelated topics. Search engines and accessibility tools expect a single H1 that summarizes the page content.

Headings inside lists

Placing headings inside list items is technically valid in some processors but creates confusing document outlines. Use bold text instead if you need emphasis within a list:

- ### Don't do this       <-- heading in a list item

- **Do this instead**     <-- bold text in a list item

Navigate Headings with MDViewer

MDViewer generates a smart table of contents from your headings automatically. Click any heading in the sidebar outline to jump to that section. Use heading-based navigation to move through long documents, and find any heading instantly with ⌘F search. Lite is free; Pro adds editing, Git history, and PDF export.

Download MDViewer

Requires macOS 13.0 or later. Intel and Apple Silicon.

FAQ

How do I create a heading in Markdown?

Start a line with one or more hash symbols (#) followed by a space and your heading text. One hash creates an H1 (# Heading), two hashes create an H2 (## Heading), and so on up to six hashes for H6. The number of hashes determines the heading level and its visual size.

How many heading levels does Markdown support?

Markdown supports six heading levels, matching the six HTML heading elements (<h1> through <h6>). H1 is the largest and most prominent, used for the document title. H6 is the smallest, rarely needed in practice. Most documents use only H1 through H3 or H4.

What is the difference between # and ## in Markdown?

A single hash (#) creates an H1 heading — the top-level heading, typically reserved for the page or document title. Two hashes (##) create an H2 heading, used for major sections within the document. H1 is larger and carries more semantic weight than H2. Best practice is to use one H1 per page and H2 for section breaks.

Can I link to a heading in Markdown?

Yes. Most Markdown processors auto-generate an id for each heading based on its text (lowercased, spaces become hyphens). Link to it with [link text](#heading-id). For example, ## Getting Started becomes #getting-started, and you link to it with [see above](#getting-started).

Should I use only one H1 per document?

Yes. The H1 represents the document’s title or main topic. Using multiple H1 headings confuses the hierarchy and can hurt SEO. Use H2 for major sections beneath the title, H3 for subsections, and so on. This creates a clean, scannable outline that benefits both readers and search engines.

What is a Setext heading in Markdown?

Setext headings are an alternative syntax that uses underline characters instead of hash symbols. A line of equal signs (===) under text creates an H1, and a line of hyphens (---) creates an H2. They only support two levels, so ATX-style headings (#) are preferred for their flexibility and support of all six levels.