Preview
Preparing...
Installation
shadcn/ui
shadcn/ui Command
pnpm dlx shadcn@latest add https://code-blocks.pheralb.dev/r/client-shiki.jsonManual
Before creating the component, make sure you have the basic structure:
reactCode Block
The main structure of the Code Block component with header and content areas.
- Create your Shiki highlighter utility:
shikiShiki Highlighter
The main highlighter utility to render syntax highlighted code.
- Create the Code Block Client component:
.tsx
"use client";
import { useEffect, useState, type ComponentProps } from "react";
import { cn } from "@/utils/cn";
import { highlight, Themes, type Languages } from "@/utils/shiki/highlight";
interface CodeblockClientShikiProps extends ComponentProps<"div"> {
code: string;
language?: Languages;
lineNumbers?: boolean;
}
const CodeblockShiki = ({
code,
language = "tsx",
lineNumbers = false,
className,
...props
}: CodeblockClientShikiProps) => {
const [highlightedHtml, setHighlightedHtml] = useState<string | null>(null);
useEffect(() => {
async function clientHighlight() {
if (!code) {
setHighlightedHtml("<pre><code></code></pre>");
return;
}
const highlighter = await highlight();
const html = highlighter.codeToHtml(code, {
lang: language,
themes: {
light: Themes.light,
dark: Themes.dark,
},
transformers: [
{
name: "AddLineNumbers",
pre(node) {
if (lineNumbers) {
const shikiStyles = node.properties.class;
node.properties.class = `${shikiStyles} shiki-line-numbers`;
}
},
},
],
});
setHighlightedHtml(html);
}
void clientHighlight();
}, [code, language, lineNumbers]);
const classNames = cn("w-full overflow-x-auto", className);
// SSR fallback
return highlightedHtml ? (
<div
className={classNames}
dangerouslySetInnerHTML={{ __html: highlightedHtml }}
{...props}
/>
) : (
<div className={classNames} {...props}>
<pre>
<code>{code}</code>
</pre>
</div>
);
};
export { CodeblockShiki };Usage
Now you can use the CodeblockShiki into your CodeBlockContent component:
.tsx
import {
CodeBlock,
CodeBlockContent,
CodeBlockHeader,
CodeBlockGroup,
CodeBlockIcon,
} from "@/components/code-block";
import { CopyButton } from "@/components/code-block/copy-button";
import { CodeblockShiki } from "@/components/code-block/client/shiki";
<CodeBlock>
<CodeBlockHeader>
<CodeBlockGroup>
<CodeBlockIcon language="ts" />
<span>Code Block + Shiki</span>
</CodeBlockGroup>
<CopyButton content={code} />
</CodeBlockHeader>
<CodeBlockContent>
<CodeblockShiki language="ts" code="console.log('Hello, world!');" />
</CodeBlockContent>
</CodeBlock>;Props
React Props
| Prop | Type | Required | |
|---|---|---|---|
| code | string | Yes | |
| language | Languages | No | |
| lineNumbers | boolean | No | |
| Included: DOMAttributes<HTMLDivElement> | |||
Languagestype is from theshikiutility.