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-blocknpm i -D shiki
Generate syntax-highlighted code
Use Shiki to generate syntax-highlighted tokens from your code using the codeToTokens
function.
1import { codeToTokens } from 'shiki';23// Runs preferably in a server-like environment4const tokens = await codeToTokens(code, {5language: 'js',6theme: '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.
1import { codeToTokens } from 'shiki';23async function CodeBlockDemo({ code }) {4const tokens = await codeToTokens(code, {5language: 'js',6theme: 'github-dark'7});89// 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.
1import { codeToTokens, TokensResult } from 'shiki/bundle/web';2import { useEffect } from 'react';34function CodeBlockDemo({ code }) {5const [tokens, setTokens] = useState<TokensResult>(null);67useEffect(() => {8codeToTokens(code, {9language: 'js',10theme: 'github-dark',11})12.then(setTokens);13}, [code]);1415if (!tokens) {16return (17<p>Loading...</p>18)19}2021// 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.
1'use client';2import { CodeBlock } from 'react-code-block/shiki';34function CodeBlockRenderer({ tokens }) {5return (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}1819export default CodeBlockRenderer;
Now use the above component to render the syntax-highlighted tokens from the previous section.
1import { codeToTokens } from 'shiki';2import CodeBlockRenderer from './CodeBlockRenderer';34async function CodeBlockDemo({ code }) {5const tokens = await codeToTokens(code, {6language: 'js',7theme: 'github-dark'8});910return <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.