You will learn to create diff blocks with the diff meta and add-remove markers, mark important lines as annotations, and combine diff, line highlighting, and captions in one block to present code changes clearly.

Technical articles that explain code changes often make readers confused reading line by line. Diff blocks solve this problem: before and after code is shown, with added and removed lines clearly marked.
Episode 8 covers diff and code annotations: how to activate diff mode via a meta string, marking added and removed lines, adding annotations in the form of line highlighting and captions, and combining everything into one neat block. After this episode, you can explain code migrations with clear visuals without a single line of text.
Diff mode is activated by adding the diff keyword to the fenced code block meta string. Inside the block contents, you mark added lines with // + and removed lines with // -. Here's an example of a diff block in TypeScript:
const a = 1;
const b = 2;
// +console.log(a + b);
// -console.log(a * b);This combination of meta string and markers produces distinctive markup. Lines with the + marker get the data-added-line attribute, while lines with the - marker get the data-removed-line attribute. Both become styling targets in CSS.
Before trying, make sure your package versions support the diff feature. Run the following commands in the terminal:
npm view rehype-pretty-code version
npm view @shikijs/transformers versionThe npm view rehype-pretty-code version command reads the latest version from the npm registry. The diff feature uses rehype-pretty-code's engine directly, so no extra dependency is needed to get started.
Diff only marks changes. To draw attention to specific lines outside the add-remove context, combine the diff meta with lines on the opening line. The full instruction looks like diff lines={2}:
const nama = "dunia";
// +console.log(`Halo, ${nama}`);
// -console.log(nama);The lines={2} meta marks the second line as a fully highlighted line, regardless of its diff status. This annotation is useful when you want to highlight a changed line without adding or removing anything, such as a variable name fix.
An annotation doesn't have to be a highlight. A caption explains why the change was made. Add caption to the meta string so readers understand the purpose of the diff without reading a long paragraph:
const daftar = [1, 2, 3];
const total = daftar.reduce((a, b) => a + b, 0);
// +console.log("total", total);The caption appears below the block and completes the title above the block. The combination of title, caption, and diff makes a block stand on its own as a complete unit of information.
The built-in data attributes make styling easy without extra classes. Target the data-added-line and data-removed-line attributes in the stylesheet:
[data-rehype-pretty-code-figure] [data-added-line] {
background-color: rgba(46, 160, 67, 0.15);
}
[data-rehype-pretty-code-figure] [data-removed-line] {
background-color: rgba(248, 81, 73, 0.15);
}Added lines get a green tint and removed lines get a red tint. These colors mimic the look of modern diff editors so readers instantly recognize the pattern.
Avoid colors that are too intense so the code tokens stay readable. Transparent backgrounds with low opacity keep text contrast high. You can also add a vertical bar on the left side of the block, similar to the line highlighting technique in episode 7.
Let's combine all the features in one block that represents a bug fix:
export function proses(input) {
if (!input) return null;
// + const bersih = input.trim();
return bersih ?? input;
}The added line is highlighted green via diff, while lines={3} adds a full annotation to that line. If you inspect DevTools, line 3 will carry both the data-added-line and data-highlighted-line attributes.
To confirm the attributes are really generated, filter the rendered output as before:
const attr = html.matchAll(/data-(added|removed|highlighted)-line/g);
console.log([...attr].map((m) => m[0]));Running this inspection script helps you understand that diff, annotations, and highlighting work on the same attribute layer and can be freely combined.
Key takeaways:
diff meta on a fenced code block.// + marker and removed lines use the // - marker.data-added-line and data-removed-line.lines for highlighting and caption for context.In episode 9 you'll learn inline code highlighting: how to disable bypassInlineCode so inline code like console.log inside a sentence is highlighted according to its language, while matching its color semantics with the surrounding code blocks.