This blog uses Rehype Pretty Code, which I introduced in a previous post.
With Rehype Pretty Code, you can display a diff by setting the language to diff, like this:
Preview
- console.log('removed')
+ console.log('added')
console.log('unchanged') ```diff
- console.log('removed')
+ console.log('added')
console.log('unchanged')
```
This is readable enough, but it feels better to display the diff with syntax highlighting still applied.
Since Rehype Pretty Code uses Shiki under the hood, you can import transformerNotationDiff from @shikijs/transformers and pass it as a Rehype Pretty Code option to get a syntax-highlighted diff.
The result we’re after
Let’s look at the result first. It ends up rendering like this:
Preview
console.log('removed');
console.log('added');
console.log('unchanged'); ```ts
console.log('removed') // [!code --]
console.log('added') // [!code ++]
console.log('unchanged')
```
Looking at the code block, there are comments at the end of the lines — styling classes get attached according to these annotations. The comments themselves are removed from the final output, so they never show up.
Setting up transformerNotationDiff
First, install @shikijs/transformers:
pnpm add -D @shikijs/transformers
Next, import transformerNotationDiff from @shikijs/transformers:
import { transformerNotationDiff } from '@shikijs/transformers';
Then pass it as a Rehype Pretty Code option. This blog uses <MDXRemote />, so I specify transformerNotationDiff() as shown below (in mdx-components.tsx) — adjust this part to fit your own setup:
export function MDX(props: JSX.IntrinsicAttributes & MDXRemoteProps) {
return (
<MDXRemote
{...props}
components={components}
options={{
mdxOptions: {
remarkPlugins: [remarkGfm],
rehypePlugins: [
rehypeSlug,
[
rehypePrettyCode,
{
theme: {
dark: 'github-dark',
light: 'github-light',
},
keepBackground: false,
defaultLang: 'plaintext',
transformers: [transformerNotationDiff()],
},
],
] as PluggableList,
},
}}
/>
);
}
Styling the diff
@shikijs/transformers doesn’t provide any styling, so you have to do that yourself.
The steps above attach the styling classes, so now we style against them.
Add the following to any CSS file. I’m using Tailwind CSS here, and the colors come from Radix Colors — change them to whatever suits you:
[data-line] {
@apply relative before:absolute before:left-0 before:px-px;
}
[data-line].diff.add {
@apply bg-[--teal-3] text-[--teal-10] before:content-['+'];
}
[data-line].diff.remove {
@apply bg-[--pink-4] text-[--pink-10] opacity-70 before:content-['-'];
}
That’s all it takes. Now you can write the following in your markdown:
```ts
console.log('removed') // [!code --]
console.log('added') // [!code ++]
console.log('unchanged')
```
And the diff renders with syntax highlighting applied:
console.log('removed');
console.log('added');
console.log('unchanged');
Wonderful!
Diffs now look the way they should.
@shikijs/transformers ships plenty of other transformers too, so I’d like to introduce more of them whenever I get the chance to use one.