Fenced Code Blocks in Markdown: Language Tags and Rendering Limits
Control how code appears in Markdown with fenced blocks, language hints, and blank-line separation rules.
01 May 2026, 11:53 UTC

Start with the rendering problem
You paste code into a Markdown file, but the published page shows it as plain text, or two separate examples appear as one continuous block. The language tag you added—such as python—does nothing visible. These issues usually come from how fenced code blocks are delimited and how downstream tools interpret the optional language hint.
The useful takeaway: use triple backticks or triple tildes to open and close a block, place the language tag immediately after the opening fence, and separate consecutive fenced blocks with a blank line. The tag is only a hint; syntax highlighting depends on your renderer and its CSS.
How fenced blocks are delimited
A fenced code block starts with a line containing three or more backticks (`) or tildes (~). It ends at the first line with the same character repeated at least three times, with no indentation greater than three spaces. Everything between those lines is treated as literal code, not Markdown.
The opening fence may be followed by a language tag, for example ```python. The tag does not change Markdown parsing. It is metadata consumed by syntax highlighters such as highlight.js or Prism.
Worked example: a Python block
```python
def greet(name):
return f"Hello, {name}"
```
In this snippet, ```python opens the block and ``` closes it. A renderer that supports language tags commonly emits HTML similar to this structure:
<pre><code class="language-python">def greet(name):
return f"Hello, {name}"</code></pre>
The exact attribute name varies by parser. Some emit class="lang-python", others add no class at all. Treat the tag as a suggestion, not a command.
Adjacent blocks must be separated
Two fenced blocks placed directly next to each other can merge into one block, depending on the parser. This example lacks a blank line:
```python
print("first")
```
```python
print("second")
```
Some parsers render this as a single code block containing both snippets. Insert a blank line between the closing fence of the first block and the opening fence of the second:
```python
print("first")
```
```python
print("second")
```
Nesting inside lists and blockquotes
A fenced block inside a list item or blockquote must be indented so the parser recognizes it as part of the parent element. Without enough indentation—or a blank line where required—the fence can close the list or blockquote prematurely.
Verification: inspect the rendered HTML
You can check behavior without changing any system state.
- Render a snippet containing
```pythonthrough your Markdown parser. - Inspect the generated HTML. Look for a
<code>element inside a<pre>element, and check whether it carries a language class such aslanguage-python. - Run the same snippet through at least two different parsers—for example, a CommonMark-compliant JavaScript parser and Python-Markdown—and compare whether blocks delimit the same way.
- Place two fenced blocks with no blank line between them and confirm whether your parser merges them or keeps them separate.
If highlighting still does not appear after the class is present, the missing piece is usually the highlighter's CSS or JavaScript on the publishing site, not the Markdown source.
Limits and common mistakes
- Language tags are renderer-specific. Some parsers ignore the tag entirely; others add a CSS class that must be styled separately.
- Highlighting is not built into Markdown. The tag alone does not color code. Your site must load a highlighter and corresponding stylesheet.
- Backticks inside code can close the fence early. If your code contains triple backticks, use four backticks to open and close, or switch to tilde fences.
- Indentation matters in lists. Fenced blocks nested in list items typically need four spaces of indentation, though exact rules vary by parser.
Practical check before publishing
Render the document locally, open the browser's developer tools, and confirm each code block appears as <pre><code> with the expected class. If two examples should be separate, verify there is a blank line between their fences in the source and two distinct blocks in the output.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.