Skip to main content

Diff Highlighting

3 min readStableIntermediate

Two ways to show a change. Put a [!code ++] or [!code --] marker in a trailing comment and the line keeps its normal syntax highlighting while picking up a green or red band. Or set the language to diff and let leading + and - characters do the work.

Quick Start

The diff language needs no metastring and no markers.

Diff
Diff
- const old = true
+ const updated = true
app/features/code/diff-highlighting.mdx
MDX
```diff
- const old = true
+ const updated = true
```

Adding Options

Comment markers keep the real language, so the changed lines stay syntax highlighted. The marker is stripped before the line renders, and a title rides along on the same fence.

lib/theme.ts
TypeScript
export function getConfig() {
  return {
    theme: 'light', 
    theme: 'dark', 
  }
}
app/features/code/diff-highlighting.mdx
MDX
```typescript title="lib/theme.ts"
export function getConfig() {
  return {
    theme: 'light',
    theme: 'dark',
  }
}
```

Advanced

Markers follow each language's comment syntax, and they stack with the rest of the metastring.

Hash comments

Configuration files use #. This block also carries a title and a highlighted line, so all three features apply at once.

docker-compose.yml
YAML
services:
  docs:
    image: owndocs:1.0 
    image: owndocs:2.0 
    restart: unless-stopped
app/features/code/diff-highlighting.mdx
MDX
```yaml {1} title="docker-compose.yml"
services:
  docs:
    image: owndocs:1.0
    image: owndocs:2.0
    restart: unless-stopped
```

Block comments

Languages that close their comments use the /* ... */ form, which works the same way as long as it ends the line.

app/globals.css
CSS
.badge {
  color: #64748b; 
  color: #0ea5e9; 
  border-radius: 0.5rem;
}
app/features/code/diff-highlighting.mdx
MDX
```css title="app/globals.css"
.badge {
  color: #64748b;
  color: #0ea5e9;
  border-radius: 0.5rem;
}
```

Options

// [!code ++]marker

Trailing comment that renders the line as an addition, with a green band. Also written # [!code ++] and /* [!code ++] */.

// [!code --]marker

Trailing comment that renders the line as a removal, with a red band and slightly reduced opacity. Same three comment styles.

difflanguage

Language identifier that marks any line whose first non-space character is + as an addition and any line starting with - as a removal.

Rules the parser follows

  • A marker only counts at the end of its line. Trailing code after the marker cancels it.
  • Spacing inside the marker is flexible. [!code ++], [!code++], and //[!code ++] all register.
  • The marker is removed from the rendered line but stays in the text the copy button hands over, because copying returns the source you wrote.
  • In a diff block, comment markers are ignored. The leading character is the only signal there, and the + or - stays visible in the output.
  • Lines opening with ++, --, +++, or --- are skipped inside a diff block, so unified-diff headers don't get painted as changes.
  • Leading whitespace is fine. An indented + inside a diff block still reads as an addition.
  • Markers mix with the rest of the metastring: a title, {} line highlighting, /pattern/, a line-number offset, and expandable all keep working.
  • Markup comments are the exception. A <!-- [!code ++] --> marker inside an html or xml block does not currently register, because the highlighter escapes the opening angle bracket before the marker is looked for. Use the diff language for markup changes.
  • A handful of languages nest a trailing comment inside a larger token — C preprocessor directives are the usual case. The band still paints there, but the marker text stays visible. Reach for the diff language when you hit one.

How it looks

Added lines get a green tint, removed lines a red tint at 70% opacity, both stretched the full width of the block. No gutter glyph is inserted, so with comment markers the color is the only signal — which is why the diff language still reads better when someone needs to copy a patch verbatim.

Was this page helpful?