Documentation
Home · Docs · Markdown · Markdown syntax highlighting for fenced code blocks

Markdown syntax highlighting for fenced code blocks

How syntax highlighting works in Markdown: add a language to a fenced code block, which renderers color code, and common language names.

To add syntax highlighting in Markdown, name the language right after the opening fence of a code block, for example ```python, and the renderer passes that language to a highlighter that colors the tokens. Highlighting is not part of the Markdown specification itself. It is provided by the renderer using a tool like highlight.js, Prism, or Rouge, so the same block can look colored on one site and plain on another.

Code fence language syntax reference

Goal Syntax
Highlight Python ```python then code, then ```
Highlight JavaScript ```js then code, then ```
No highlighting ``` with no language
Common aliases js, py, sh, ts, rb, json

Markdown syntax highlighting key facts

  • Add highlighting by writing the language name as the info string right after the opening code fence, with no space.
  • Markdown itself adds no color, so it writes the language into a class on the <code> element for a separate highlighter to read.
  • Highlighting is renderer dependent, so the same document can be colored on one tool, themed differently in another, and plain where no highlighter runs.
  • Common highlighters include highlight.js and Prism in the browser, and Rouge, used by Jekyll and GitHub Pages, on the server.
  • Common identifiers include python, js, ts, bash, ruby, json, yaml, html, css, and sql, with aliases that vary by highlighter.
  • An unknown or missing language falls back to plain, uncolored code rather than failing.

A language identifier is a renderer hint

The word after the opening code fence is commonly called an info string or language identifier. Markdown preserves the code without it; the renderer uses it to choose a highlighter and CSS class.

Use a specific identifier such as javascript, python, json, or bash only when it matches the content. Aliases differ between highlight.js, Prism, Rouge, Chroma, and other engines, so an identifier may work in one site and not another. If highlighting fails, the code should still be readable as plain preformatted text. See fenced code blocks for delimiter rules.

Basic syntax

Add the language identifier right after the opening fence, with no space. The block is a normal fenced code block. The language name is the only extra step.

Markdown

```python
def greet(name):
    return f"Hello, {name}"
```

Rendered output

def greet(name):
    return f"Hello, {name}"

HTML output

<pre><code class="language-python">def greet(name):
    return f"Hello, {name}"
</code></pre>

The Markdown parser does not color anything by itself. It writes the language into a class on the <code> element, then a separate highlighter reads that class and wraps each token in a colored <span>. If no highlighter runs, the code still appears, just without color. For the fence mechanics themselves, see fenced code blocks.

How highlighting actually happens

Markdown itself has no colors. The pipeline has two stages: the Markdown parser turns ```python into a <code class="language-python"> element, then a highlighting library scans that element and adds token spans. Common highlighters include highlight.js and Prism in the browser, and Rouge, used by Jekyll and GitHub Pages, on the server.

HTML before highlighting

<pre><code class="language-js">const x = 1;</code></pre>

HTML after a highlighter runs

<pre><code class="language-js"><span class="token keyword">const</span> x <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span></code></pre>

Because the second stage is optional and renderer specific, the same Markdown can look colored on one site and plain on another. The colors themselves come from a CSS theme that styles those token classes.

Language identifiers and aliases

Highlighters accept a canonical language name and usually several aliases. The exact list depends on the highlighter, so an alias that works in one may not work in another.

Markdown

```js
let total = items.reduce((a, b) => a + b, 0);
```

Rendered output

let total = items.reduce((a, b) => a + b, 0);

Common identifiers include python or py, javascript or js, typescript or ts, bash or sh, ruby or rb, json, yaml, html, css, and sql. Use the canonical name when you are unsure, since it is the most portable across highlighters.

Unknown or missing languages

If you use a language the highlighter does not recognize, most renderers fall back to plain, uncolored code rather than failing. The same happens when you leave the info string empty.

Markdown

```notareallanguage
plain uncolored text
```

Rendered output

plain uncolored text

An unrecognised identifier normally falls back to unhighlighted code, although the exact fallback depends on the rendering pipeline. Use a blank fence deliberately for plain output like logs and shell transcripts.

Highlighting is renderer dependent

The single most important point about syntax highlighting is that it is a renderer feature, not a Markdown feature. No Markdown flavor defines colors. What the flavors define is the info string, the slot where the language name lives. Whether that name produces color, and which colors, depends entirely on the tool rendering the Markdown.

This means the same document can be fully colored on GitHub, colored with a different theme in your editor, and completely plain in a minimal renderer that ships no highlighter. None of those outcomes is wrong. They reflect different rendering setups around the same standard input.

Flavor differences

No Markdown flavor performs highlighting. The table below tracks whether a flavor defines the info string, the language slot that highlighters read, and how highlighting is typically wired up. Highlighting itself is always renderer dependent.

Flavor Language identifier support Notes
CommonMark Yes (info string) Defines the info string and puts the first word in a class. Ships no highlighter. Coloring is up to the renderer.
GitHub Flavored Markdown (GFM) Yes (info string) Same info string as CommonMark. GitHub highlights server side with Rouge based on the language word.
MultiMarkdown Verify Accepts a language identifier on fenced blocks and emits a language class. Actual highlighting depends on the tool rendering the output.
Markdown Extra Yes (language class) The language name becomes a class on the code element. Highlighting is done by a separate highlighter, not by Markdown Extra.
Pandoc Yes (info string and attributes) Reads the language word or an attribute class, and can highlight to HTML with a chosen highlight style using a built in highlighter.

The pattern is consistent. Many modern renderers accept a language name on the fence, while the colouring is handled by a separate highlighter or conversion pipeline. CommonMark and GFM define the info string precisely. GitHub uses Rouge on its servers. Markdown Extra emits a language class for an external highlighter. Pandoc is the outlier that can produce highlighted HTML directly, controlled by a highlight style option. The MultiMarkdown cell is marked Verify because highlighting there depends heavily on which tool consumes the output.

Other platforms (Slack, Discord, Obsidian, Notion)

  • Slack: creates code blocks from triple backticks but ignores the language word, so there is no highlighting.
  • Discord: applies highlighting when you name a language after the opening backticks.
  • Obsidian and Notion: both highlight fenced code blocks based on the language identifier.

For the full comparison of how flavors differ across all elements, see Markdown flavors.

How Markdific renders it

Markdific renders fenced code blocks with syntax highlighting, using the language identifier from the info string to color the code. Syntax highlighting for fenced code blocks is a confirmed Markdific feature. A block with no language, or an unrecognized language, renders as plain monospace code.

Try it in the Markdific online editor.

Common mistakes and gotchas

  • Expecting Markdown to color code on its own. Markdown only records the language name. A separate highlighter does the coloring. Without one, the code is plain.
  • A space between the fence and the language. Write the language immediately after the fence. A space can stop the parser from reading it as the language.
  • Using an alias the highlighter does not know. Aliases vary by highlighter. If color is missing, try the canonical language name.
  • Assuming the same colors everywhere. Colors come from a theme, which differs across sites and editors. Do not rely on specific colors.
  • Naming a language for plain output. For logs and transcripts, leave the info string blank so the block stays plain.
  • Confusing highlighting with formatting. Highlighting never changes the code text. It only wraps tokens in colored spans.

Best practices

  • Always name the language when the code has one, so any highlighter in the pipeline can color it.
  • Prefer canonical language names over aliases for portability across renderers.
  • Leave the info string blank for output that has no language, such as shell transcripts and logs.
  • Do not depend on specific colors. Themes vary, and some renderers show no color at all.
  • Keep code accurate and complete. Highlighting improves readability but does not fix broken code.

HTML equivalent

The Markdown parser converts a language identifier into a class on the <code> element. A highlighter then adds token spans inside that element. The base HTML is the same as any fenced code block.

Markdown

```sql
SELECT name FROM users WHERE active = 1;
```

HTML output (before a highlighter runs)

<pre><code class="language-sql">SELECT name FROM users WHERE active = 1;
</code></pre>

FAQ

How do you add syntax highlighting in Markdown? Name the language right after the opening fence of a code block, for example the word python after three backticks. The renderer adds that language as a class and a highlighter colors the tokens.

Is syntax highlighting part of the Markdown spec? No. Markdown flavors define the info string, the slot where the language name goes, but no flavor defines colors. Highlighting is done by the renderer using a tool like highlight.js, Prism, or Rouge.

Why is my code block not highlighted? Common causes are a missing language name, a space between the fence and the language, an alias the highlighter does not recognize, or a renderer that ships no highlighter at all. Without a highlighter, code is always plain.

What languages can I use for highlighting? It depends on the highlighter, but common identifiers include python, javascript, typescript, bash, ruby, json, yaml, html, css, and sql, along with short aliases like js and py.

Does GitHub highlight Markdown code blocks? Yes. GitHub highlights fenced code blocks server side using Rouge, based on the language word you put after the opening backticks.

Do the highlight colors look the same everywhere? No. Colors come from a CSS theme, which differs between sites and editors. The same code can appear in different colors, or with no color, depending on the renderer.

Does highlighting change the code itself? No. Highlighting only wraps tokens in colored spans. The code text stays exactly as you typed it.

How do you show a code block without highlighting? Leave the info string blank, so the opening fence is just three backticks with no language. The block renders as plain monospace code, which is the right choice for logs, shell transcripts, and any output that has no language.

What is the difference between highlight.js, Prism, and Rouge? They are separate highlighters. Highlight.js and Prism run in the browser and are common in docs sites and blogs, while Rouge runs on the server and powers Jekyll and GitHub Pages. Each supports a slightly different set of language names and aliases and ships its own themes.

Can you change the syntax highlighting theme in Markdown? Not from Markdown itself. Colors come from a CSS theme that the site or editor applies to the token classes, so you change the theme in the renderer or its stylesheet, not in the Markdown source.

What language should I use for a shell or terminal block? Use bash, sh, or shell for shell commands so the highlighter colors them. For a raw terminal transcript that mixes commands and output, leave the info string blank so the block stays plain.

Sources and compatibility references

Use these primary references for syntax rules. Renderer behaviour can still vary by version and configuration, so preview important documents in their final destination.