Rehype plugin to add line numbers to code blocks and allow highlighting of desired code lines
npm install rehype-highlight-code-linesIf you find rehype-highlight-code-lines useful in your projects, consider supporting my work.
Your sponsorship means a lot 💖
Be the first sponsor and get featured here and on my sponsor wall.
Thank you for supporting open source! 🙌
[![npm version][badge-npm-version]][url-npm-package]
[![npm downloads][badge-npm-download]][url-npm-package]
[![publish to npm][badge-publish-to-npm]][url-publish-github-actions]
[![code-coverage][badge-codecov]][url-codecov]
[![type-coverage][badge-type-coverage]][url-github-package]
[![typescript][badge-typescript]][url-typescript]
[![license][badge-license]][url-license]
This package is a [unified][unified] ([rehype][rehype]) plugin that wraps each line of code in a container, enabling code block numbering and line highlighting.
[unified][unified] is a project that transforms content with abstract syntax trees (ASTs) using the new parser [micromark][micromark]. [remark][remark] adds support for markdown to unified. [mdast][mdast] is the Markdown Abstract Syntax Tree (AST) which is a specification for representing markdown in a syntax tree. [rehype][rehype] is a tool that transforms HTML with plugins. [hast][hast] stands for HTML Abstract Syntax Tree (HAST) that rehype uses.
This plugin enables line numbering for code blocks and highlights specific lines as needed.
rehype-highlight-code-lines is ideal for adding line numbers to code blocks and highlighting specific lines.
rehype-highlight-code-lines is NOT code highlighter and does NOT provide code highlighting! You can use a code highlighter for example [rehype-highlight][rehype-highlight] to highlight the code, then use rehype-highlight-code-lines after.
> [!IMPORTANT]
> If your code highlighter already provides numbering and highlighting code lines, don't use rehype-highlight-code-lines!
> \
> \
> You can use rehype-highlight-code-lines even without a code highlighter.
This package is suitable for ESM only. In Node.js (version 16+), install with npm:
``bash`
npm install rehype-highlight-code-lines
or
`bash`
yarn add rehype-highlight-code-lines
In a code fence, right after the language of the code block:
+ Use curly braces {} to specify a range of line numbers to highlight specific lines.showLineNumbers
+ Add to enable line numbering.
\\\[language] {2,4-6} showLineNumbers
\\\[language] showLineNumbers {2}
\\\[language] {1-3}
\\\[language] showLineNumbers
You can use the specifiers without a language:
\\\{5} showLineNumbers
\\\showLineNumbers {5}
\\\{2,3}
\\\showLineNumbers
Say we have the following markdown file, example.md:
``markdown`javascript {2} showLineNumbers`
let a1;
let a2;
let a3;``
I assume you use rehype-highlight for code highlighting. Our module, example.js, looks as follows:
`javascript
import { read } from "to-vfile";
import remark from "remark";
import gfm from "remark-gfm";
import remarkRehype from "remark-rehype";
import rehypeHighlight from "rehype-highlight";
import rehypeHighlightLines from "rehype-highlight-code-lines";
import rehypeStringify from "rehype-stringify";
main();
async function main() {
const file = await remark()
.use(gfm)
.use(remarkRehype)
.use(rehypeHighlight)
.use(rehypeHighlightLines)
.use(rehypeStringify)
.process(await read("example.md"));
console.log(String(file));
}
`
Now, running node example.js you will see that each line of code is wrapped in a span, which has appropriate class names (code-line, numbered-code-line, highlighted-code-line) and line numbering attribute data-line-number.
`html`
let a1;
class="code-line numbered-code-line highlighted-code-line" data-line-number="2">
let a2;
let a3;
Without rehype-highlight-code-lines, the lines of code wouldn't be in a span.
`html`
let a1;
let a2;
let a3;
Note: hljs prefix comes from rehype-highlight.
rehype-highlight-code-lines runs on elements with directives like showLineNumbers and range number in curly braces like {2-4,8}. That directives can be passed as a word in markdown ( ``ts showLineNumbers {2-4,8} ) or as a class and attribute in HTML ().
The inverse occurs when the option showLineNumbers is true. All are processed and numbered. Then ( `ts noLineNumbers ), or as a class () can be used to prevent processing.
The class directives can be with dash or without, or camel cased.
See some example usage as HTML class and attributes (only opening : tags are provided, the rest is omitted.)
``html
`
Say we have the following HTML fragment in a example.md:
`markdown`
let a1;
let a2;
let a3;
I assume you use rehype-highlight for code highlighting. Our module, example.js, looks as follows:
`javascript
import { read } from "to-vfile";
import remarkParse from "remark-parse";
import remarkRehype from "remark-rehype";
import rehypeRaw from "rehype-raw";
import rehypeHighlight from "rehype-highlight";
import rehypeHighlightLines from "rehype-highlight-code-lines";
import rehypeStringify from "rehype-stringify";
main();
async function main() {
const file = await unified()
.use(remarkParse)
.use(remarkRehype, { allowDangerousHtml: true })
.use(rehypeRaw)
.use(rehypeHighlight)
.use(rehypeHighlightLines)
.use(rehypeStringify)
.process(await read("example.md"));
console.log(String(file));
}
`
Now, running node example.js you will see that each line of code is wrapped in a span, which has appropriate class names (code-line, numbered-code-line, highlighted-code-line) and line numbering attribute data-line-number.
`html`
let a1;
class="code-line numbered-code-line highlighted-code-line" data-line-number="2">
let a2;
let a3;
All options are optional and have default values.
`typescript
type HighlightLinesOptions = {
showLineNumbers?: boolean; // default is "false"
keepOuterBlankLine?: boolean; // default is "false"
};
use(rehypeHighlightLines, HighlightLinesOptions);
`
#### showLineNumbers
It is a boolean option which is for all code to be numbered.
By default, it is false.
`javascript`
use(rehypeHighlightLines, {
showLineNumbers: true,
});
Now, all code blocks will become numbered.
If you want to exclude a specific code block not to be numbered, use noLineNumbers.
\\\[language] noLineNumbers {2}
\\\[language] noLineNumbers
\\\noLineNumbers
If you want to exclude a specific code block not to be numbered in HTML fragment (in ) use no-line-numbers class. In that case, the directive could be with dash, or without, or camel cased.
Sometimes you may want to start the line numbering from a specific number. In that cases, use showLineNumbers=[number] in code blocks. For example, below, the code block's line numbering will start from number 8.
\\\[language] {2} showLineNumbers=8
\\\[language] showLineNumbers=8
\\\showLineNumbers=8
If you want to start the line numbering from a specific number in HTML fragment (in
) usedata-start-numberingattribute.keep-outer-blank-linekeepOuterBlankLine####
falseIt is a boolean option which is for all code blocks have an empty line container in the beginning and at the end. I added this option in case you want to have an empty code line on the edges for whatever reason.
By default, it is
.`javascript`
use(rehypeHighlightLines, {
keepOuterBlankLine: true,
});keepOuterBlankLineNow, all code blocks will have one empty code line on each edge.
If you want a specific code block has empty code line on the edges, use
.\\
\[language] keepOuterBlankLine\
\\keepOuterBlankLineIn HTML fragment use
class. In that case, the directive could be with dash, or without, or camel cased.`$3
typescript`
// line numbering will occur as per directive "showLineNumber" and code-line containers will be inline element
use(rehypeHighlightLines);// all code blocks will be numbered by default and code-line containers will be inline element
use(rehypeHighlightLines, {
showLineNumbers: true,
});rehype-highlightAn example screen snapshot from a working app:
!markdown code block input
!markdown code block resultHere you can find some demo applications below which the
andrehype-highlight-code-linesare used together:next-mdx-remote-client
+ demo blog application usingwithinNext.js app routernext-mdx-remote-client
+ demo blog application usingwithinNext.js pages router`Styling
The following styles can be added for line highlighting and line numbering to work correctly:
Choose the colors as you wish!
css`
.parent-container-of-pre {
display: grid; / in order { overflow-x: auto; } works in child/
}pre,
pre code {
background-color: var(--color-code-background);direction: ltr;
text-align: left;
white-space: pre;
word-spacing: normal;
word-break: normal;
line-height: 1.2;
tab-size: 2;
hyphens: none;
}pre {
padding: 0.5rem 1rem;
border: 1px solid var(--color-text-weak);
border-radius: 5px;overflow-x: auto;
}pre > code {
float: left;
min-width: 100%;
}.code-line {
min-width: 100%;
padding-left: 12px;
padding-right: 12px;
margin-left: -12px;
margin-right: -12px;
border-left: 4px solid transparent; / prepare for highlighted code-lines /display: inline-block;
}.code-line.inserted {
background-color: var(--color-inserted-line); / inserted code-line (+) /
}.code-line.deleted {
background-color: var(--color-deleted-line); / deleted code-line (-) /
}.highlighted-code-line {
background-color: var(--color-highlighted-line);
border-left: 4px solid var(--color-highlighted-line-indicator);
}.numbered-code-line::before {
content: attr(data-line-number);margin-left: -8px;
margin-right: 16px;
width: 1rem;
color: var(--color-text-weak);
text-align: right;display: inline-block;
}hastSyntax tree
This plugin modifies the
(HTML abstract syntax tree).HighlightLinesOptionsTypes
This package is fully typed with [TypeScript][url-typescript].
The plugin exports the type
.rehype-parseCompatibility
This plugin works with
version 1+,rehype-stringifyversion 1+,rehypeversion 1+, and unified version4+.rehype-highlight-code-linesSecurity
Use of
involves rehype (hast), but doesn't lead to cross-site scripting (XSS) attacks.remark-flexible-code-titlesMy Plugins
I like to contribute the Unified / Remark / MDX ecosystem, so I recommend you to have a look my plugins.
$3
remark-flexible-containers
– Remark plugin to add titles or/and containers for the code blocks with customizable properties
-remark-ins
– Remark plugin to add custom containers with customizable properties in markdown
-ins
– Remark plugin to addelement in markdownremark-flexible-paragraphs
-remark-flexible-markers
– Remark plugin to add custom paragraphs with customizable properties in markdown
-mark
– Remark plugin to add customelement with customizable properties in markdownremark-flexible-toc
-vfile.data
– Remark plugin to expose the table of contents viaor via an option referenceremark-mdx-remove-esm
-rehype-pre-language
– Remark plugin to remove import and/or export statements (mdxjsEsm)$3
pre
– Rehype plugin to add language information as a property toelementrehype-highlight-code-lines
-rehype-code-meta
– Rehype plugin to add line numbers to code blocks and allow highlighting of desired code lines
-code.data.meta
– Rehype plugin to copytocode.properties.metastringrehype-image-toolkit
-![]()
– Rehype plugin to enhance Markdown image syntaxand Markdown/MDX media elements (,