Shiki Support

Shiki Support

React Code Block also supports rendering code highlighted using Shiki (opens in a new tab) library. Shiki uses the same highlighting engine that is used by VS Code, resulting in a very high-quality syntax highlighting and support for any VS Code theme.

Installation

Start by installing shiki as a dependency or a dev-dependency(depending on how you are using it) alongside react-code-block:

npm i react-code-block
npm i -D shiki

Generate syntax-highlighted code

Use Shiki to generate syntax-highlighted tokens from your code using the codeToTokens function.

1
import { codeToTokens } from 'shiki';
2
3
// Runs preferably in a server-like environment
4
const tokens = await codeToTokens(code, {
5
language: 'js',
6
theme: 'github-dark'
7
});

Where should the above code go?

Because of the nature of Shiki library, typically it is used on the server-side(or build time) for generating syntax-highlighted code, and then a client-side code block component in React consumes this data to actually render the HTML on the webpage. Depending on your framework, there should be a way to run code in such environments.

Use React Server Components (opens in a new tab) if you are using App Router, or getServerSideProps / getStaticProps functions in Pages Router.

CodeBlockDemo.js
1
import { codeToTokens } from 'shiki';
2
3
async function CodeBlockDemo({ code }) {
4
const tokens = await codeToTokens(code, {
5
language: 'js',
6
theme: 'github-dark'
7
});
8
9
// Code from next section goes here.
10
}

How do I run it completely client-side?

There are ways to run Shiki completely on the client-side like it's mentioned in their docs (opens in a new tab). An example is shown below. Be mindful of the bundle size and amount of JavaScript you are loading on client-side just for syntax highlighting.

1
import { codeToTokens, TokensResult } from 'shiki/bundle/web';
2
import { useEffect } from 'react';
3
4
function CodeBlockDemo({ code }) {
5
const [tokens, setTokens] = useState<TokensResult>(null);
6
7
useEffect(() => {
8
codeToTokens(code, {
9
language: 'js',
10
theme: 'github-dark',
11
})
12
.then(setTokens);
13
}, [code]);
14
15
if (!tokens) {
16
return (
17
<p>Loading...</p>
18
)
19
}
20
21
// Code from next section goes here.
22
}
šŸ’”

The above process is async and would show a "Loading..." text to the user while syntax highlight is in process. To eliminate this, either move the syntax highlighting code to a server-like environment or consider using the Prism highlighter.

Render the syntax-highlighted code

Once you have the syntax-highlighted tokens from your code, you can now use React Code Block package to render the code. First, create a new file with a Client Component as shown. Notice how the import is from react-code-block/shiki here.

CodeBlockRenderer.js
1
'use client';
2
import { CodeBlock } from 'react-code-block/shiki';
3
4
function CodeBlockRenderer({ tokens }) {
5
return (
6
<CodeBlock tokens={tokens}>
7
<CodeBlock.Code className="bg-gray-900 p-6 rounded-xl shadow-lg">
8
<div className="table-row">
9
<CodeBlock.LineNumber className="table-cell pr-4 text-sm text-gray-500 text-right select-none" />
10
<CodeBlock.LineContent className="table-cell">
11
<CodeBlock.Token />
12
</CodeBlock.LineContent>
13
</div>
14
</CodeBlock.Code>
15
</CodeBlock>
16
);
17
}
18
19
export default CodeBlockRenderer;

Now use the above component to render the syntax-highlighted tokens from the previous section.

CodeBlockDemo.js
1
import { codeToTokens } from 'shiki';
2
import CodeBlockRenderer from './CodeBlockRenderer';
3
4
async function CodeBlockDemo({ code }) {
5
const tokens = await codeToTokens(code, {
6
language: 'js',
7
theme: 'github-dark'
8
});
9
10
return <CodeBlockRenderer tokens={tokens} />
11
}

You can now customize the CodeBlock component however you like with features such as line numbers, line highlighting, etc. as documented here.