MD003 - Heading style should be consistent¶
Aliases: heading-style
What this rule does¶
Ensures all headings in your document use the same formatting style.
Why this matters¶
- Readability: Consistent heading styles make documents easier to scan and navigate
- Professionalism: Mixed heading styles look unprofessional and unpolished
- Tool compatibility: Some tools expect consistent heading formats for navigation features
Examples¶
✅ Correct (using # style)¶
✅ Correct (using underline style)¶
✅ Correct (using setext-with-atx style)¶
First Level Heading
==================
Second Level Heading
------------------
### Third Level Heading
#### Fourth Level Heading
✅ Correct (using setext-with-atx-closed style)¶
First Level Heading
==================
Second Level Heading
------------------
### Third Level Heading ###
#### Fourth Level Heading ####
❌ Incorrect (mixed styles)¶
🔧 Fixed¶
Configuration¶
[MD003]
style = "consistent" # Options: "consistent", "atx", "atx-closed", "setext", "setext-with-atx", "setext-with-atx-closed"
Style options explained¶
"consistent"(default): Use the most prevalent style in your document (in case of a tie, ATX style is preferred as it's most widely supported)"atx": Use # symbols (# Heading)"atx-closed": Use # symbols at both ends (# Heading #)"setext": Use underlines (equals for level 1, dashes for level 2)"setext-with-atx": Use underlines for level 1-2, # symbols for level 3-6"setext-with-atx-closed": Use underlines for level 1-2, # symbols with closing # for level 3-6
Note: Underline style only works for level 1 and 2 headings. Level 3 and below must use # symbols.
Automatic fixes¶
This rule can automatically convert all headings to match your configured style or the most prevalent style in the document.
Markdown with Gherkin¶
Under the mdg flavor, MD003 steers every heading to plain ATX whatever style
is configured. Markdown with Gherkin parses ATX headings only — one to six #
characters followed by a space — so a Setext heading never becomes a Gherkin
node, and a closing sequence leaks into the node's name, making # Feature: F #
a node named F #.
When a fixed style other than atx was configured explicitly and the override
applies in MDG, rumdl prints one [config warning] per process. The default
consistent style and an explicit atx do not warn.
❌ Incorrect¶
✅ Correct¶
Under any other flavor the configured style is applied as usual.
Limitation¶
Converting a Setext heading changes its source text, not just its Markdown
presentation. In an MDG document without an explicit # Feature: heading,
Cucumber may derive the feature name from the leading Markdown content; adding
the ATX marker can therefore add a literal # and following space to that
parsed feature name.
This occurs in Cucumber's testdata/good/misc.feature.md. Avoid Setext headings
in MDG, or disable MD003 when that AST must remain unchanged.
See Markdown with Gherkin Flavor for the full flavor specification.
Learn more¶
- CommonMark specification for headings - Technical details about heading syntax
- Setext headings - Details about underline-style headings