Focus & Code Diff in Nuxt Content Code Blocks
Custom code blocks are essential for my blog as my articles usually contain a lot of code snippets. My blog is powered by Nuxt Content v2, which is a Nuxt 3 module. I already wrote an article about how you can create custom code blocks using Nuxt Content v2.
In this article, I'll show you how to focus certain lines of your code or highlight a diff inside a custom code block. This feature is adopted from Vitepress which provides similar functionality.
Focus Lines
Sometimes, you want to focus on certain lines of your code. For example, you want to highlight the most important lines of your code snippet.
In our example, we can do this by adding // [!code focus]
in the line that should be highlighted:
The above code results in the following code block:
If you hover over the code block, you can see that the whole code is visible without any highlighting.
Diff Lines
Another use case is to highlight a diff inside a code block. For example, you want to show the difference between two code snippets.
In our example, we can do this by adding // [!code ++]
in the line that should be highlighted as added and // [!code --]
in the line that should be highlighted as removed:
The above code results in the following code block:
Implementation
Info
Update from January 2024: The following implementation is only necessary if you don't use shikiji, which provides transformers for the focus and diff syntax.
Let's now take a look at the implementation of this feature.
We opt out of the default code highlighting provided by Nuxt Content and handle it ourselves. We use Shiki to highlight the code, which is also used by Nuxt Content under the hood. The process of custom rendering of code blocks is documented in the Shiki README.
Let's start by writing a composable that returns a Shiki highlighter instance. As we'll have multiple Shiki instances on the same page we need to make sure that we only create one instance and reuse it. This is achieved by putting the highlighter instance in a ref
outside of the composable.
Additionally, the composable exports the renderToHtml
function from Shiki which we use later to render the highlighted code to HTML:
Now it's time to create the custom code block component.
Info
If you never did this before, I'd recommend you to read my article about how to create a custom code block with Nuxt Content v2 first.
The basic structure of our custom ProseCode
component looks like this:
Let's extend that component by using our useShikiHighlighter
composable to highlight the code:
Let's go through the code step by step:
- We create a
html
ref that will contain the highlighted code as HTML - We use the
useShikiHighlighter
composable to get the highlighter instance and therenderToHtml
function - We watch the
highlighter
ref and callrenderToHtml
when the highlighter is available - We use the
codeToThemedTokens
function to get the tokens for the code - We use the
renderToHtml
function to render the tokens to HTML - We use the
elements
option to customize the HTML output of the code block. Theline
element can be used to customize the HTML output of each line. We use it to add adiv
around each line to make it possible to highlight single lines. - We use the
v-html
directive to render the highlighted code as HTML
You can now easily extend the code to highlight lines if certain comments are inside the code passed via props:
The idea is quite simple: We look for our predefined set of comments inside the code and add a custom class to the line if the comment is present. We can then use this class to style the line accordingly.
Of course, you also need to remove these comments from the code before passing it to the codeToThemedTokens
function. Otherwise, the comments would be rendered as HTML.
StackBlitz Demo
The code for this article is interactively available on StackBlitz:
Conclusion
In this article, you learned how to use the Nuxt content module to render code blocks that highlight single lines or highlight lines that were added or removed. By opting out of the default code highlighting of the Nuxt content module, you can use the Shiki library to render any custom code block that you need.
I like such small customizations that can make a big difference in the user experience. I hope you enjoyed this article and learned something new.
If you liked this article, follow me on Twitter to get notified about new blog posts and more content from me.
Alternatively (or additionally), you can subscribe to my weekly Vue newsletter:
Lazy Load Vue Component When It Becomes Visible
In this blog post, I'll show you how a simple mechanism to lazy load your Vue components if they become visible using the Intersection Observer API.
Unlocking the Power of v-for Loops in Vue With These Useful Tips
Looping through arrays and objects is a common task in Vue applications. The v-for directive is the perfect tool for this job. It is mighty, and you can use it in many different ways. In this article, I will show you some valuable tips and tricks to get the most out of the v-for directive.