markdown11 min read

Markdown Superscript and Subscript: The Complete 2026 Guide

The exact syntax for markdown superscript and subscript, which platforms support ^text^ and ~text~, and the HTML fallback that works everywhere.

TL;DR

Markdown superscript is ^text^ and subscript is ~text~ — but only in Pandoc and a handful of derivatives. GitHub, GitLab, Reddit, npm, and most MDX setups ignore both. The portable answer is the HTML fallback: <sup>text</sup> and <sub>text</sub>. Use those for chemistry (H<sub>2</sub>O), math (x<sup>2</sup>), and ordinals (1<sup>st</sup>) and you'll get correct rendering everywhere.

Markdown has two raised/lowered text syntaxes — ^text^ for superscript and ~text~ for subscript. Both come from Pandoc's extension to CommonMark. Neither is part of the base CommonMark or GitHub Flavored Markdown specs, which means most platforms render the carets and tildes as literal characters or break in unexpected ways.

This guide gives you the exact syntax, which platforms support it, the HTML fallback that works everywhere, and the MDX gotcha that crashes builds if you're not careful.

Want the bigger picture first? This detailed crash course covers markdown's core syntax before you reach for extensions like superscript and subscript:

Detailed markdown crash course covering core syntax (Oston Code Cypher).

The short answer#

Two syntaxes, one universal fallback:

Markdown
Superscript shorthand:  E = mc^2^
Superscript HTML:       E = mc<sup>2</sup>
 
Subscript shorthand:    H~2~O
Subscript HTML:         H<sub>2</sub>O

The HTML fallback wins on portability. Every renderer that accepts inline HTML — which is almost all of them — handles <sup> and <sub> correctly. The shorthand is shorter but unreliable.

Superscript syntax in markdown#

Wrap the text you want raised in single carets:

Markdown
The area of a circle is πr^2^.
Einstein gave us E = mc^2^.

In a Pandoc-compatible renderer, that produces πr² and E = mc². In GitHub or most other tools, you'll see literal carets. To handle multi-word superscripts, you need to escape the spaces with a backslash:

Markdown
This is the 2^nd\ generation^ model.

Spaces inside the markers terminate the superscript on most parsers, so backslash-escaped spaces are how Pandoc keeps the whole phrase raised. It's awkward. The HTML version is cleaner:

Markdown
This is the 2<sup>nd generation</sup> model.

For accessibility, both render to the same <sup> element under the hood — see MDN's sup element docs for the semantics. Screen readers handle <sup> and <sub> correctly; styling raised text with CSS does not.

Subscript syntax in markdown#

Wrap the text in single tildes:

Markdown
Water is H~2~O.
Sulfuric acid is H~2~SO~4~.

Tilde syntax collides with strikethrough on most platforms. GitHub and GitLab use ~~text~~ for strikethrough. A single ~text~ is silently ignored on GitHub and may render as strikethrough on tools that accept single-tilde strikes. If you see your subscript come out struck-through, this is why.

The HTML fallback sidesteps the collision entirely:

Markdown
Water is H<sub>2</sub>O.
Sulfuric acid is H<sub>2</sub>SO<sub>4</sub>.

That renders identically on GitHub, GitLab, MDX, Docusaurus, and every other markdown tool that respects inline HTML.

Which platforms actually support ^ and ~#

Here's the real compatibility picture — the part most guides skip:

Platform^text^~text~<sup> / <sub>
GitHub (GFM)❌ (treats as strike)
GitLab
Pandoc
Reddit✅ (sup only)❌ (HTML stripped)
Discord
Obsidian❌ by default❌ by default
VS Code preview
npm README✅ (limited)
Markdown Here
MDX (remark-gfm)

The GitHub Flavored Markdown spec confirms what the table shows: GFM defines emphasis, strikethrough, tables, task lists, and autolinks. It does not define superscript or subscript shorthand. If you want raised or lowered text on GitHub, the HTML tags are the only option.

Pandoc is the one place the shorthand truly shines — it's the original source of the superscript and subscript extension, and Pandoc-derived tools (some static site generators, academic writing pipelines) inherit it.

Reddit is a special case: it supports superscript via ^text (no closing caret, just a leading one), and it stops at the next space unless you wrap with parentheses: ^(multi word). It does not support subscript at all.

Use the HTML fallback when in doubt#

If you're writing documentation that needs to render across multiple platforms — GitHub README, your docs site, npm package page, blog mirror — use the HTML tags. They're verbose but they work.

Pick the right tag

Use <sup> for raised text (exponents, ordinals, footnote markers). Use <sub> for lowered text (chemistry subscripts, mathematical indices).

Write the content between the tags

No special escaping needed inside the tags. Spaces, punctuation, and numbers all work.

Markdown
The 1<sup>st</sup> law of thermodynamics applies to H<sub>2</sub>O.

Verify rendering on your target platform

Render the file in your actual destination (GitHub preview, your docs build, npm's package page). The shorthand often passes local preview but fails on the deployed site.

For MDX specifically, the HTML tags are valid JSX, so the parser accepts them with zero configuration. This is why Dokly's visual MDX editor handles <sup> and <sub> cleanly while shorthand requires a remark plugin to recognize.

Real-world examples#

Copy these directly into your docs:

Chemistry#

Markdown
Water: H<sub>2</sub>O
Carbon dioxide: CO<sub>2</sub>
Sulfuric acid: H<sub>2</sub>SO<sub>4</sub>
Glucose: C<sub>6</sub>H<sub>12</sub>O<sub>6</sub>
Sodium bicarbonate: NaHCO<sub>3</sub>

Math and physics#

Markdown
Area of a circle: A = πr<sup>2</sup>
Pythagorean theorem: a<sup>2</sup> + b<sup>2</sup> = c<sup>2</sup>
Mass-energy equivalence: E = mc<sup>2</sup>
Scientific notation: 6.022 × 10<sup>23</sup>

Ordinals#

Markdown
1<sup>st</sup>, 2<sup>nd</sup>, 3<sup>rd</sup>, 4<sup>th</sup>
The 21<sup>st</sup> century
March 21<sup>st</sup>, 2026

Footnote markers#

Markdown
This claim needs a citation<sup>1</sup>.
See the appendix<sup>[2]</sup> for details.

These all render correctly on GitHub, GitLab, MDX, Docusaurus, and any markdown tool that accepts inline HTML. If you need similar formatting tricks across platforms, see also markdown blockquote rendering across platforms and horizontal lines in markdown.

Escaping carets and tildes#

When you need a literal ^ or ~ and your renderer interprets them as superscript/subscript markers, escape with a backslash:

Markdown
The XOR operator is \^, and the home directory is \~.

On platforms that ignore the shorthand entirely (GitHub, GitLab, most MDX setups), the escape is unnecessary — the character already renders as itself:

Markdown
The XOR operator is ^, and the home directory is ~.

Inside fenced code blocks and inline code, never escape. The renderer treats code spans as literal text:

Markdown
`array[i] ^ array[j]`  → renders as: array[i] ^ array[j]

If you're writing for multiple destinations, pick one rule and stick to it. The simplest is: never use the shorthand, always use the HTML tags. You'll never need to escape anything and the output is identical everywhere.

Superscript and subscript in MDX#

MDX parses your file as a hybrid of markdown and JSX. That has two consequences for superscript and subscript:

  1. The ^text^ and ~text~ shorthand is not recognized by default. MDX uses remark plugins like remark-gfm, and GFM does not include the superscript/subscript extension. You'd need a custom plugin like remark-supersub to make the shorthand work.

  2. The HTML-style <sup> and <sub> tags always work, because they're valid JSX elements. MDX renders them as React components.

So in MDX, just use the tags:

MDX
The escape velocity of Earth is 11.2 km/s = 1.12 × 10<sup>4</sup> m/s.
 
Carbonic acid (H<sub>2</sub>CO<sub>3</sub>) forms when CO<sub>2</sub> dissolves in water.

The MDX gotcha that crashes builds. Writing < directly followed by a digit anywhere in your MDX — like <2 seconds or <5 users — makes the parser think you're opening a JSX tag named 2 or 5. The build fails with a confusing error about unexpected tokens. Always put a space around comparison operators or rephrase: "under 2 seconds", "fewer than 5 users". This is unrelated to <sup> and <sub>, but it bites people writing technical content.

MDX's JSX parsing rules explain the parser's behavior in detail. The short version: anything that looks like a tag is parsed as JSX, so use HTML tags for inline formatting and avoid raw < characters anywhere else.

For more on what works inside MDX files, see every MDX component Dokly supports.

Common errors and how to fix them#

These are the real symptoms developers hit and the fix for each.

"My superscript shows the literal carets"#

You wrote E = mc^2^ and got E = mc^2^ in the output. Your renderer doesn't support the Pandoc shorthand. Switch to HTML:

Markdown
E = mc<sup>2</sup>

"GitHub strikes through my subscript"#

You wrote H~2~O and got H2O with a line through it. GitHub interpreted the tildes as strikethrough markers. Use the HTML tag:

Markdown
H<sub>2</sub>O

"npm README ignores my HTML tags"#

npm's package page renderer is conservative about inline HTML. Most tags work, but some are stripped. <sup> and <sub> are usually fine; if you see them disappear, check that you're not inside a code block, and that the surrounding markdown is well-formed.

"MDX build fails with 'unexpected token'"#

Look for < immediately followed by a digit anywhere in the file — not just near your sup/sub tags. Even something like Response time was <100ms buried in a paragraph will crash the build. Rephrase to "under 100ms" or add a space: < 100ms.

"Obsidian doesn't render my superscript"#

Obsidian doesn't enable the Pandoc shorthand by default and doesn't accept all HTML. Install a community plugin for superscript/subscript shorthand, or use <sup> and <sub> which Obsidian does accept in its preview.

"Discord won't format any of it"#

Discord's markdown is intentionally minimal. There's no way to do real superscript or subscript in Discord messages — you'll need Unicode characters (²³⁴, ₂₃₄) if you absolutely must convey raised or lowered text.

"Reddit superscript works but breaks on spaces"#

Use parentheses to group: ^(multi word phrase). Reddit's syntax is ^text (no closing caret) and stops at the first whitespace unless you wrap.

For other markdown formatting issues that vary by platform, see centering text in markdown and indenting content in markdown — both have similar cross-platform quirks.

Frequently Asked Questions#

Does GitHub support markdown superscript and subscript?#

Yes, but only via the HTML <sup> and <sub> tags. GitHub Flavored Markdown does not recognize ^text^ or ~text~ syntax — those will render as literal characters or trigger strikethrough. Use H<sub>2</sub>O or x<sup>2</sup> in any GitHub README, issue, or comment and it will display correctly.

What's the difference between ^text^ and <sup>text</sup>?#

They produce the same visual output — raised text — but compatibility differs. The ^text^ shorthand is a Pandoc extension and works in tools like Pandoc, Reddit (for superscript only), and some static site generators. The <sup> HTML tag works in every markdown renderer that accepts inline HTML, which is almost all of them. When in doubt, use the HTML tag.

Why does my subscript syntax break on GitHub?#

GitHub treats ~~text~~ as strikethrough and either ignores single-tilde ~text~ or interprets it as a strike. To get subscript on GitHub, use <sub>text</sub> instead. The same applies to GitLab, Bitbucket, and most npm README renderers.

How do I write H2O or CO2 with proper subscripts in markdown?#

Write H<sub>2</sub>O and CO<sub>2</sub>. This renders correctly on every major platform — GitHub, GitLab, MDX, Docusaurus, VS Code preview, and most static site generators. The shorthand H~2~O only works in Pandoc and a few derivatives, so it's not portable.

Can I use superscript and subscript in MDX files?#

Yes. Use the HTML-style <sup> and <sub> tags — they're valid JSX, so MDX parses them without complaint. Avoid the ^text^ and ~text~ shorthand because MDX relies on remark-gfm and similar plugins that don't recognize them by default. Also avoid writing < directly before a digit anywhere in MDX, because the parser tries to read it as a JSX tag and the build will fail.

How do I escape a literal caret or tilde in markdown?#

Prefix it with a backslash: \^ renders as ^ and \~ renders as ~. Inside fenced code blocks, no escaping is needed — characters render literally. If your platform doesn't recognize the shorthand anyway (like GitHub), no escape is required since the character already renders as itself.

Where to go next#

If you're tired of memorizing which platform supports which markdown extension, try Dokly free — the visual editor handles superscript, subscript, and the rest of the cross-platform quirks for you, so you write the content and ship.

Written by Gautam Sharma, Founder Dokly

Building Dokly — documentation that doesn't cost a fortune. AI-ready docs out of the box.

Follow on X →
Start for free

Ready to build better docs?

Start creating beautiful, AI-ready documentation with Dokly today. No git, no YAML, no friction.

Get started free