Markdown Horizontal Rule (Divider Line) — Syntax Tutorial
When you're writing a long document, inserting a horizontal rule (also called a horizontal line or divider) between topics makes the structure much clearer. The syntax is dead simple — just three characters — but there are a few gotchas worth knowing about.
Basic Markdown Horizontal Rule Syntax
There are three ways to create a horizontal rule in Markdown, all producing identical results:
---
***
___All three render as a horizontal line spanning the full width of the content area. The corresponding HTML tag is <hr>.
According to the CommonMark specification, these are also called "thematic breaks." You can use whichever one you prefer — the key requirement is at least three characters, and they must be on their own line.
More than three works too. ----- or ******* produce the same result.
Three Dashes (Most Common)
Content for the first section.
---
Content for the second section.This is the most widely used approach. About 92% of Markdown files on GitHub use --- for horizontal rules.
Three Asterisks
Content for the first section.
***
Content for the second section.The asterisk approach has one advantage: it never conflicts with heading syntax (more on that below). If you're concerned about that, asterisks are a safe alternative. Spaces between them are allowed too — * * * is valid syntax.
Three Underscores
Content for the first section.
___
Content for the second section.Underscores are the least popular option, but equally valid across all major Markdown parsers.
Syntax Rules in Detail
The syntax is simple, but there are a few rules you need to follow — otherwise your horizontal rule might not render at all, or worse, turn into something else.
Must Be on Its Own Line
The line with the horizontal rule can only contain the rule characters (with optional surrounding spaces), nothing else:
<!-- Correct -->
Some text
---
More text
<!-- Wrong: other text on the same line -->
--- this is not a horizontal ruleAdd Blank Lines Before and After
This is especially important. Without a blank line above ---, many parsers treat it as an H2 heading underline (Setext-style heading) instead of a horizontal rule:
<!-- This becomes an H2 heading, NOT a horizontal rule! -->
Some text
---
<!-- This correctly creates a horizontal rule -->
Some text
---
More textI ran into this once while writing a CHANGELOG — the version numbers were right above ---, and they got turned into giant headings with no divider in sight. The fix is simple: just add a blank line above ---.
Don't Mix Characters
Each horizontal rule line must use only one type of character. Mixing them doesn't work:
<!-- Wrong: mixing dashes and asterisks -->
--*
-*-
<!-- Correct: one character type only -->
---At Least Three Characters
Two characters aren't enough — you need three or more:
<!-- Wrong: only two -->
--
<!-- Correct: three or more -->
---
-----Rendering Differences Across Platforms
All major platforms support all three syntax methods, but the visual output varies slightly:
| Platform | Supported | Rendering Style |
|---|---|---|
| GitHub | Yes | Thin gray line, ~1px, with ~24px vertical margin |
| GitLab | Yes | Thin gray line |
| Yes | Thin line | |
| Stack Overflow | Yes | Thin line |
| Notion | Yes | Use --- or /divider command — converts to native divider block |
| Obsidian | Yes | Thin line that follows theme colors |
| VS Code Preview | Yes | Default browser <hr> styling |
| Typora | Yes | Thin line, customizable via CSS |
| Discord | No | No horizontal rule support |
| Slack | No | No horizontal rule support |
Using the HTML <hr> Tag as an Alternative
If the Markdown syntax doesn't work in your environment (some specialized setups), you can use the HTML <hr> tag directly:
Some text
<hr>
More textMost platforms that support Markdown also support inline HTML, so <hr> works almost everywhere. The result is the same as the Markdown syntax.
Customizing Horizontal Rule Styles
Markdown itself doesn't support style customization, but if your platform allows HTML and CSS, there are a few ways to make your dividers look better.
Inline Styles
Add a style attribute directly to the <hr> tag:
<hr style="border: 2px solid #333; width: 60%; margin: 2em auto;">This renders a dark gray, 60% width, centered horizontal rule. GitHub and most static site generators support this. However, Obsidian's live preview and editors that strip HTML may not.
Global CSS
If you have your own site or blog, it's better to define horizontal rule styles globally in your CSS rather than writing inline styles everywhere:
hr {
border: none;
border-top: 2px dashed #ccc;
margin: 2em 0;
}This way, every --- in your Markdown automatically picks up the custom style.
Custom Rendering with markdown-it
If you're using a static site generator based on markdown-it (like Eleventy or VuePress), you can override the rendering rule to completely customize the <hr> output.
const markdownIt = require("markdown-it")
const mdSetup = markdownIt()
mdSetup.renderer.rules.hr = (tokens, idx, options, env, self) => {
return '<hr class="custom-divider" />'
}Now every horizontal rule in your Markdown will render as an <hr> with a custom-divider class, which you can style however you like with CSS.
Practical Use Cases
Horizontal rules used in the right places improve readability. Used too often, they create visual clutter. Here are good scenarios for them:
Project introduction and feature overview...
---
## Changelog
### v2.0.0
- Added user management
- Fixed login timeout issue
---
### v1.0.0
- Initial release- Between README sections: Separate installation from usage instructions
- Between changelog versions: Mark each version entry
- Between body text and appendices/footnotes: Distinguish main content from supplementary info
- At thematic shifts: Between two completely unrelated topics
That said, if you find yourself adding a horizontal rule every two or three paragraphs, you probably need headings instead of dividers. Horizontal rules work best where a heading doesn't quite fit but you still want a clear visual break.
Which Method Should You Pick?
Honestly, any of them work. Consistency matters more than which specific character you choose. Here's my take:
| Method | Pros | Cons | Recommended For |
|---|---|---|---|
--- | Most common, most intuitive | Can conflict with headings without blank line | Everyday use (just remember the blank line) |
*** | No heading conflict | Less commonly used | Team style guides worried about heading ambiguity |
___ | No heading conflict | Rarely used | Personal preference |
I personally stick with --- and just remember to add a blank line above it. If you're writing a style guide for a team, *** is the safest pick because it completely eliminates any chance of confusion with headings.
FAQ
Why did my --- turn into a heading?
Because when --- appears directly below a line of text, it's parsed as a Setext-style H2 heading. Add a blank line above it to fix this.
Can two dashes -- create a horizontal rule?
No. You need at least three. Two dashes may be interpreted as a strikethrough or em dash in some parsers, but never as a horizontal rule.
Can I change the color or thickness of a horizontal rule?
Not in pure Markdown. If your platform supports HTML, you can use a styled <hr> tag, or define styles globally in your site's CSS.
What's the difference between a blank line and a horizontal rule?
A blank line just adds paragraph spacing. A horizontal rule renders a visible line across the page. If all you need is spacing, use blank lines — no horizontal rule necessary.
Why don't Discord and Slack support horizontal rules?
These platforms implement a limited subset of Markdown and don't include the thematic break syntax. To simulate a divider on Discord or Slack, you can use emoji-based alternatives like ————— or - - -.