Code blocks & syntax highlighting

The language hint that gives code its colors

When you write ```python above a code block, VS Code, GitHub, ChatGPT, and dozens of other tools automatically colorize keywords, strings, and comments. Here's exactly how that works — and what falls apart when you leave the hint out.

Illustration: color bands emerging from a label, human figure placing the trigger

What you actually see — and why

Open a Markdown file in VS Code and write a fenced code block with a language hint. The moment you type those characters, the code inside turns from flat grey text into a color-coded display where keywords glow blue, strings shine green, and comments fade to muted grey. That visual treatment is called syntax highlighting, and it's one of the most useful things Markdown does for code.

The color isn't stored anywhere in the Markdown source. There are no color codes, no CSS classes, no hidden tags. The raw source is just plain text with a language word after the opening backticks. Everything visual is computed at render time.

Without language hint — dead text
no hint
def greet(name): message = "Hello, " + name # return the greeting return message result = greet("world") print(result)
With ```python — highlighted
python
def greet(name): message = "Hello, " + name # return the greeting return message result = greet("world") print(result)

The Markdown source for both blocks is identical except for one word on the opening fence line. The renderer does all the work.

How the coloring actually happens

When a renderer encounters a fenced code block with a language hint, it runs the content through a tokenizer — a program that reads the text and classifies each fragment by its role in that programming language. The tokenizer knows that def is a Python keyword, that text between double quotes is a string literal, that a line starting with # is a comment.

Each classified fragment gets wrapped in a <span> with a CSS class like .keyword, .string, or .comment. Then a color theme — just a CSS file — maps those classes to actual colors. VS Code ships dozens of themes that all reuse the same token classes but apply different colors to them. That's why your code looks different in "Monokai" vs. "GitHub Light" vs. "Dracula" even though the underlying structure is identical.

InputRaw Markdown text
Language ID```python, ```js …
TokenizerClassifies fragments
Spans + classes.keyword .string …
Color themeCSS maps class→color
OutputColored HTML

The most common tokenizer libraries used across tools are highlight.js (used by many Markdown renderers and ChatGPT), Prism.js (used by many static site generators and documentation tools), and TextMate grammars (the format VS Code, GitHub, and Sublime Text use). They all do roughly the same job with slightly different language coverage and accuracy.

Why do some tools get highlighting slightly wrong? Tokenizing is hard. Real programming languages have context-dependent rules that simple pattern matching misses. A string containing # might look like a comment to a naive tokenizer. Most tools use heuristics and grammars that are good enough for reading purposes but not a full language parser. VS Code's grammars are among the most accurate because they're the same ones used to power actual IntelliSense.

The Markdown syntax — exactly how to write it

A fenced code block uses three backticks to open and three to close. The language identifier goes immediately after the opening backticks, no space:

markdown source
```python def hello(): return "world" ```

Three backticks, language name, newline, code, newline, three backticks. That's the entire syntax. The language identifier is case-insensitive in most renderers — Python, PYTHON, and python all work.

You can also use tildes (~~~) instead of backticks in standard CommonMark Markdown. Backticks are more widely supported and more commonly used.

Common language identifiers

Each language has one canonical identifier and often several accepted aliases. These are the ones you're likely to use:

Language Primary identifier Common aliases
Pythonpythonpy
JavaScriptjavascriptjs
TypeScripttypescriptts
C#csharpcs, c#
C / C++c / cppc++
Javajava
Gogogolang
Rustrustrs
HTMLhtmlhtm
CSScssscss, sass
SQLsql
Shell / Bashbashsh, shell, zsh
PowerShellpowershellps1, pwsh
JSONjson
YAMLyamlyml
XMLxmlxaml
Markdownmarkdownmd
Plain text (no color)texttxt, plain

If the renderer doesn't recognize the identifier, it typically falls back to displaying the block as plain monospace text — no error, just no color. This is the same result as omitting the hint entirely.

Where syntax highlighting works

Tool / Platform Supports highlighting Notes
VS Code Yes Full TextMate grammar support, theme-aware, hundreds of languages
GitHub / GitLab / Bitbucket Yes Both in README files and in inline code review comments
ChatGPT Yes Uses highlight.js; AI automatically adds the language hint when generating code
Claude Yes Same — AI adds the hint automatically, renderer colorizes it
Obsidian Yes In preview mode and Live Preview; theme-dependent colors
Notion Yes Supports common languages; language selector in the block UI
Slack No Renders code blocks as monospace but ignores the language hint
Microsoft Teams No Same — monospace block, no coloring
Microsoft Word No Word has no Markdown renderer; code blocks must be converted first (see below)
Gmail / Outlook (web) No Email composers don't render Markdown at all
Jupyter Notebooks Yes In Markdown cells; language cells always highlighted by kernel language
GitHub Pages / Jekyll / Hugo Yes Uses Rouge or Prism; theme must be configured in site CSS

The language hint is preserved even when highlighting doesn't render. If you write your Markdown with correct hints in VS Code and then paste it somewhere that doesn't support highlighting — like Slack — the text still displays in a monospace block. The hint string (python) might appear as a label or be silently ignored, but it doesn't break anything. You lose the color but keep the structure.

Why AI chatbots add the hint automatically

When ChatGPT, Claude, or Gemini generates a code response, the language identifier appears automatically. You didn't ask for it — the model adds it because it was trained on vast amounts of Markdown where code blocks consistently carried language hints. The model learned that well-formed code blocks include the hint and reproduces that pattern.

This is one of those places where training on human-written Markdown produces a concretely useful behavior. The AI has essentially internalized the convention.

It also means that the colorized output you see in a ChatGPT or Claude response is not coming from the AI — the AI outputs plain text with a language hint. The interface (the web application around the model) is doing the rendering and the coloring. If you copy the raw Markdown source from the copy button and paste it into a plain text file, you'll see the fence and the identifier but no color — because your text editor has no renderer.

What happens when you convert to Word

Word documents don't have a syntax highlighting engine. A .docx file can contain a code block — a paragraph with a monospace font and a grey background — but it won't colorize tokens based on programming language. The structure is preserved; the colors are not.

When a Markdown-to-Word converter processes a fenced code block, the best it can do is output a styled paragraph in a monospace font (typically Consolas or Courier New) with a light background fill to visually separate it from prose. The language hint may be used to add a label, but the individual tokens won't be colored unless the converter explicitly runs its own tokenizer and applies character-level text color — which very few do, because it produces enormous file sizes and fragile formatting.

This is a reasonable tradeoff. Documents sent by email or submitted as reports are rarely expected to contain syntax-highlighted code. Monospace + background is already a significant improvement over plain paragraph text. If you need color in Word specifically, the most robust approach is to use a dedicated code formatter like Notepad++ → Copy as RTF and paste the result as rich text, or use a VS Code extension that exports colorized HTML which Word can import.

Web tool

Paste Markdown. Get a proper Word document.

markdownword.com converts your Markdown — including fenced code blocks — into a correctly structured .docx file with real heading styles, real lists, and code blocks in a styled monospace font. No manual reformatting.

Practical tips

Always add the language hint

There is no cost to adding it and a clear benefit in any renderer that supports highlighting. Make it a habit: whenever you open a fenced code block, immediately type the language identifier. This takes under a second and improves readability everywhere the Markdown is rendered.

Use text when you explicitly want no color

If you're showing output, logs, or content that looks like code but shouldn't be colorized — command output, file paths, error messages — use ```text. This tells the renderer "this is a code block, use monospace, but don't try to colorize it". It produces cleaner results than omitting the hint, because some renderers attempt auto-detection on unhinted blocks and get it wrong.

Use bash or sh for command-line instructions

Shell commands are some of the most commonly written code blocks in documentation and AI responses. ```bash highlights the command name, flags, and arguments in a way that makes multi-step instructions much easier to scan.

bash
# Install dependencies and start the dev server npm install npm run dev --port 3000

Check the identifier if highlighting looks wrong

If your code block is colorized but the colors seem off — comments treated as strings, keywords not highlighted — the most common cause is a wrong or unsupported language identifier. Try the canonical name from the table above. If that doesn't help, try text to suppress auto-detection attempts.

Further reading: Mermaid diagrams — the format AI actually draws in · Math in Markdown · Jupyter notebooks and Markdown — AI-native by design