Last time, we set up syntax highlighting with Rehype Pretty Code (rehype-pretty-code) and changed the theme.
This time, let’s go a step further and add line numbers and highlight specific lines inside code blocks.
Rehype Pretty Code lets you configure a highlighted code block through its meta string.
For example, you write markdown like the following — the meta string is the showLineNumbers title="add.js" {3} part:
```js showLineNumbers title="add.js" {3}
const add = (a, b) => a + b
add(2, 3) // 5
```
With the styling from this post applied, that markdown renders as a code block titled add.js, with line numbers down the side and the third line highlighted.
However, Rehype Pretty Code doesn’t provide the styling itself, so you need to write the CSS separately.
Let’s get to work, starting with the preparation for applying CSS.
Preparing to apply CSS to Rehype Pretty Code
First, create a file to hold the CSS (styles/syntax-highlighting.css):
touch styles/syntax-highlighting.css
Then import it from styles/global.css:
@tailwind base;
@tailwind components;
@tailwind utilities;
@import './syntax-highlighting.css';
Now we’re ready to apply CSS, so let’s write it. The CSS below uses Tailwind CSS’s @apply.
Styling the code block as a whole
After Rehype Pretty Code runs, the figure element wrapping each code block gets a data-rehype-pretty-code-figure data attribute. So you can style the whole block like this:
figure[data-rehype-pretty-code-figure] {
/* ... */
}
Here’s the styling I’m using, along with styles for the child pre element. The colors come from Radix Colors:
figure[data-rehype-pretty-code-figure] {
@apply mt-4 w-full rounded-[--radius-base] border border-[--border] bg-[--iris-2];
}
figure[data-rehype-pretty-code-figure] pre {
@apply overflow-x-auto py-4;
}
Next, let’s style the lines inside the code block.
Styling lines
Rehype Pretty Code adds a data-line data attribute to each line in a code block, so line styling targets data-line:
figure[data-rehype-pretty-code-figure] [data-line] {
@apply mt-0 border-l-2 border-transparent px-4;
}
The transparent border applied here is what gets colored when a line is highlighted.
Now let’s set up highlighting itself and style it.
Highlighting specific lines
Marking lines in markdown
To highlight lines with Rehype Pretty Code, write {3} in the markdown code fence.
For a range, write {1-3}; for multiple lines, {1,3}.
```js title="add.js" {3}
const add = (a, b) => a + b
add(2, 3) // 5
```
With {3} in the fence, the third line gets a data-highlighted-line data attribute.
Styling the highlighted lines
Style data-highlighted-line by setting border-color and background-color:
[data-highlighted-line] {
@apply !border-[--iris-8] !bg-[--iris-3];
}
Next up: the code block title.
Code block titles
Setting a title in markdown
To set a title, add title="..." to the markdown code fence:
```js {3} title="add.js"
const add = (a, b) => a + b
add(2, 3) // 5
```
Using title="..." inserts an element like this into the HTML:
<figcaption
data-rehype-pretty-code-title=""
data-language="js"
data-theme="default"
>
add.js
</figcaption>
The value of title="..." (here, add.js) ends up inside a figcaption carrying the data-rehype-pretty-code-title data attribute.
Let’s style that element.
Styling the title
Here I style the title itself, plus the pre element that sits right after it:
figcaption[data-rehype-pretty-code-title] {
@apply text-small border-border border-b px-4 py-1 text-[--iris-9];
}
figcaption[data-rehype-pretty-code-title] + pre {
@apply mt-0;
}
Finally, let’s add and style line numbers.
Line numbers
To display line numbers, add showLineNumbers to the markdown code fence:
```js {3} title="add.js" showLineNumbers
const add = (a, b) => a + b
add(2, 3) // 5
```
Then write the CSS that increments and displays the line counter, plus a bit of extra styling:
code[data-line-numbers] {
counter-reset: line;
}
code[data-line-numbers] > [data-line]::before {
display: inline-block;
width: 12px;
margin-right: 1rem;
color: gray;
text-align: right;
content: counter(line);
counter-increment: line;
}
code[data-line-numbers-max-digits='2'] > [data-line]::before {
width: 1.25rem;
}
code[data-line-numbers-max-digits='3'] > [data-line]::before {
width: 1.75rem;
}
code[data-line-numbers-max-digits='4'] > [data-line]::before {
width: 2.25rem;
}
With that, you get nicely presented code blocks like the ones described above.
Wrapping up
With Rehype Pretty Code and a bit of your own CSS, you can get syntax highlighting that’s both beautiful and easy to follow.
There’s no default CSS provided, so you do have to write it yourself — but no default styling also means total freedom, which I appreciate.
Since Rehype Pretty Code uses Shiki, you can also use Shiki’s transformers to display diffs with syntax highlighting applied. Check that out if you’re interested.