December 8, 2024
Test
Passing your code snippet to the codeToHtml
function with the lang
and theme
specified, it will return a highlighted HTML string that you can embed in your page. The generated HTML contains inline style for each token, so you don't need extra CSS to style it.
import { codeToHtml } from 'shiki';
const code = 'const a = 1'; // input code
const html = await codeToHtml(code, {
lang: 'javascript',
theme: 'vitesse-dark',
});
console.log(html); // highlighted html string
Meta#
<html></html>
Usage#
import {
transformerNotationDiff,
// ...
} from '@shikijs/transformers';
import { codeToHtml } from 'shiki';
const code = `console.log('hello')`;
const html = await codeToHtml(code, {
lang: 'ts',
theme: 'nord',
transformers: [
transformerNotationDiff(),
// ...
],
});
Unstyled#
Transformers only applies classes and does not come with styles; you can provide your own CSS rules to style them properly.
Matching Algorithm#
We found that the algorithm for matching comments in v1 is sometime conterintuitive, where we are trying to fix it in a progressive way. Since v1.29.0, we introduced a new matchAlgorithm
option to most of the transformer for you to toggle between different matching algorithms. Right now, the default is v1
which is the old algorithm, and v3
is the new algorithm. When Shiki v3 is landed, the default will be v3
.
const html = await codeToHtml(code, {
lang: 'ts',
theme: 'nord',
transformers: [
transformerNotationDiff({
matchAlgorithm: 'v3',
}),
],
});
matchAlgorithm: 'v3'
#
In v3
, the matching algorithm will start counting from the line below the comment:
// [\!code highlight:2]
console.log('highlighted');
console.log('highlighted');
console.log('not highlighted');
Two Slash#
// this is a normal code block
import { createHighlighterCore } from 'shiki/core';
import { createJavaScriptRegexEngine } from 'shiki/engine/javascript';
const highlighter = await createHighlighterCore({
engine: createJavaScriptRegexEngine(),
});
// this will run Twoslash
import { createHighlighterCore } from 'shiki/core';
import { createJavaScriptRegexEngine } from 'shiki/engine/javascript';
const highlighter = await createHighlighterCore({
engine: createJavaScriptRegexEngine(),
});
Transformers#
transformerNotationDiff
#
Use [!code ++]
and [!code --]
to mark added and removed lines.
```ts
console.log('hewwo'); // [\!code --]
console.log('hello'); // [\!code ++]
console.log('goodbye');
```
Renders (with custom CSS rules):
console.log('hewwo');
console.log('hello');
console.log('goodbye');
// [!code ++]
outputs:<span class="line diff add">
// [!code --]
outputs:<span class="line diff remove">
- The outer
<pre>
tag is modified:<pre class="has-diff">
::: details HTML Output
<!-- Output (stripped of `style` attributes for clarity) -->
<pre class="shiki has-diff"> <!-- Notice `has-diff` -->
<code>
<span class="line"></span>
<span class="line"><span>function</span><span>()</span><span></span><span>{</span></span>
<span class="line diff remove"> <!-- Notice `diff` and `remove` -->
<span></span><span>console</span><span>.</span><span>log</span><span>(</span><span>'</span><span>hewwo</span><span>'</span><span>) </span>
</span>
<span class="line diff add"> <!-- Notice `diff` and `add` -->
<span></span><span>console</span><span>.</span><span>log</span><span>(</span><span>'</span><span>hello</span><span>'</span><span>) </span>
</span>
<span class="line"><span></span><span>}</span></span>
<span class="line"><span></span></span>
</code>
</pre>
:::
transformerNotationHighlight
#
Use [!code highlight]
to highlight a line.
```ts
console.log('Not highlighted');
console.log('Highlighted'); // [\!code highlight]
console.log('Not highlighted');
```
Renders (with custom CSS rules):
console.log('Not highlighted');
console.log('Highlighted');
console.log('Not highlighted');
// [!code highlight]
outputs:<span class="line highlighted">
- The outer
<pre>
tag is modified:<pre class="has-highlighted">
You can also highlight multiple lines with a single comment:
```ts
// [\!code highlight:3]
console.log('Highlighted');
console.log('Highlighted');
console.log('Not highlighted');
```
```ts
console.log('Not highlighted');
// [\!code highlight:1]
console.log('Highlighted');
console.log('Not highlighted');
```
Renders:
console.log('Highlighted');
console.log('Highlighted');
console.log('Not highlighted');
console.log('Not highlighted');
console.log('Highlighted');
console.log('Not highlighted');
transformerNotationWordHighlight
#
Use [!code word:Hello]
to highlight the word Hello
in any subsequent code.
```ts
// [\!code word:Hello]
const message = 'Hello World';
console.log(message); // prints Hello World
```
Renders (with custom CSS rules):
const message = 'Hello World';
console.log(message); // prints Hello World
Outputs: <span class="highlighted-word">Hello</span>
for matched words.
You can also specify the number of lines to highlight words on, e.g. [!code word:Hello:1]
will only highlight occurrences of Hello
on the next line.
```ts
// [\!code word:Hello:1]
const message = 'Hello World';
console.log(message); // prints Hello World
```
Renders:
const message = 'Hello World';
console.log(message); // prints Hello World
transformerNotationFocus
#
Use [!code focus]
to focus a line.
```ts
console.log('Not focused');
console.log('Focused'); // [\!code focus]
console.log('Not focused');
```
Renders (with custom CSS rules):
console.log('Not focused');
console.log('Focused');
console.log('Not focused');
- Outputs:
<span class="line focused">
- The outer
<pre>
tag is modified:<pre class="has-focused">
You can also focus multiple lines with a single comment:
```ts
// [\!code focus:3]
console.log('Focused');
console.log('Focused');
console.log('Not focused');
```
Renders:
console.log('Focused');
console.log('Focused');
console.log('Not focused');
transformerNotationErrorLevel
#
Use [!code error]
and [!code warning]
to mark a line with an error and warning levels.
```ts
console.log('No errors or warnings');
console.error('Error'); // [\!code error]
console.warn('Warning'); // [\!code warning]
```
- Outputs:
<span class="line highlighted error">
for errors - Outputs:
<span class="line highlighted warning">
for warnings - The outer
<pre>
tag is modified:<pre class="has-highlighted">
With some additional CSS rules, you can make it look like this:
console.log('No errors or warnings');
console.error('Error');
console.warn('Warning');
transformerRenderWhitespace
#
Render whitespaces (tabs and spaces) as individual spans, with classes tab
and space
.
With some additional CSS rules, you can make it look like this:
???
::: details Example CSS
.vp-code .tab,
.vp-code .space {
position: relative;
}
.vp-code .tab::before {
content: '⇥';
position: absolute;
opacity: 0.3;
}
.vp-code .space::before {
content: '·';
position: absolute;
opacity: 0.3;
}
:::
transformerMetaHighlight
#
Highlight lines based on the meta string provided on the code snippet.
```js {1,3-4}
console.log('1');
console.log('2');
console.log('3');
console.log('4');
```
Renders (with custom CSS rules):
console.log('1');
console.log('2');
console.log('3');
console.log('4');
- Outputs:
<span class="line highlighted">
for included lines.
transformerMetaWordHighlight
#
Highlight words based on the meta string provided on the code snippet.
```js /Hello/
const msg = 'Hello World';
console.log(msg);
console.log(msg); // prints Hello World
```
Renders (with custom CSS rules):
const msg = 'Hello World';
console.log(msg); // prints Hello World
Outputs: <span class="highlighted-word">Hello</span>
for matched words.
transformerCompactLineOptions
#
Support for shiki
's lineOptions
that is removed in shiki
.
transformerRemoveLineBreak
#
Remove line breaks between <span class="line">
. Useful when you set display: block
to .line
in CSS.
transformerRemoveNotationEscape
#
Transform // [\!code ...]
to // [!code ...]
.
Avoid rendering the escaped notation syntax as it is.
transformerStyleToClass
#
Convert Shiki's inline styles to unique classes.
Class names are generated based on the hash value of the style object with the prefix/suffix you provide. You can put this transformer in multiple highlights passes and then get the CSS at the end to reuse the exact same styles. As Shiki doesn't handle CSS, it's on your integration to decide how to extract and apply/bundle the CSS.
For example:
import { transformerStyleToClass } from '@shikijs/transformers';
import { codeToHtml } from 'shiki';
const toClass = transformerStyleToClass({
classPrefix: '__shiki_',
});
const code = `console.log('hello')`;
const html = await codeToHtml(code, {
lang: 'ts',
themes: {
dark: 'vitesse-dark',
light: 'vitesse-light',
},
defaultColor: false,
transformers: [toClass],
});
// The transformer instance exposes some methods to get the CSS
const css = toClass.getCSS();
// use `html` and `css` in your app
HTML output:
<pre
class="shiki shiki-themes vitesse-dark vitesse-light __shiki_9knfln"
tabindex="0"
><code><span class="line">
<span class="__shiki_14cn0u">console</span>
<span class="__shiki_ps5uht">.</span>
<span class="__shiki_1zrdwt">log</span>
<span class="__shiki_ps5uht">(</span>
<span class="__shiki_236mh3">'</span>
<span class="__shiki_1g4r39">hello</span>
<span class="__shiki_236mh3">'</span>
<span class="__shiki_ps5uht">)</span>
</span></code></pre>
CSS output:
.__shiki_14cn0u {
--shiki-dark: #bd976a;
--shiki-light: #b07d48;
}
.__shiki_ps5uht {
--shiki-dark: #666666;
--shiki-light: #999999;
}
.__shiki_1zrdwt {
--shiki-dark: #80a665;
--shiki-light: #59873a;
}
.__shiki_236mh3 {
--shiki-dark: #c98a7d77;
--shiki-light: #b5695977;
}
.__shiki_1g4r39 {
--shiki-dark: #c98a7d;
--shiki-light: #b56959;
}
.__shiki_9knfln {
--shiki-dark: #dbd7caee;
--shiki-light: #393a34;
--shiki-dark-bg: #121212;
--shiki-light-bg: #ffffff;
}