Shogo Oshima

—Web Developer

Sketches Blog About
GitHub X

Adding line numbers and highlighting lines with Rehype Pretty Code

Others

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.

References