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.
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.
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:
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 |
|---|---|---|
| Python | python | py |
| JavaScript | javascript | js |
| TypeScript | typescript | ts |
| C# | csharp | cs, c# |
| C / C++ | c / cpp | c++ |
| Java | java | — |
| Go | go | golang |
| Rust | rust | rs |
| HTML | html | htm |
| CSS | css | scss, sass |
| SQL | sql | — |
| Shell / Bash | bash | sh, shell, zsh |
| PowerShell | powershell | ps1, pwsh |
| JSON | json | — |
| YAML | yaml | yml |
| XML | xml | xaml |
| Markdown | markdown | md |
| Plain text (no color) | text | txt, 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.
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.
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.