<div class="container">
<h1>Hello, world!</h1>
</div>
"use client"
import { CodeBlock, createShikiAdapter } from "@chakra-ui/react"
import type { HighlighterGeneric } from "shiki"
const file = {
code: `
<div class="container">
<h1>Hello, world!</h1>
</div>
`,
language: "html",
title: "index.html",
}
const Demo = () => {
return (
<CodeBlock.AdapterProvider value={shikiAdapter}>
<CodeBlock.Root code={file.code} language={file.language}>
<CodeBlock.Content>
<CodeBlock.Code>
<CodeBlock.CodeText />
</CodeBlock.Code>
</CodeBlock.Content>
</CodeBlock.Root>
</CodeBlock.AdapterProvider>
)
}
const shikiAdapter = createShikiAdapter<HighlighterGeneric<any, any>>({
async load() {
const { createHighlighter } = await import("shiki")
return createHighlighter({
langs: ["tsx", "scss", "html", "bash", "json"],
themes: ["github-dark"],
})
},
theme: "github-dark",
})
用法
¥Usage
import { CodeBlock } from "@chakra-ui/react"
<CodeBlock.AdapterProvider>
<CodeBlock.Root>
<CodeBlock.Header>
<CodeBlock.Title />
<CodeBlock.Control>
<CodeBlock.CopyTrigger />
<CodeBlock.CollapseTrigger />
</CodeBlock.Control>
</CodeBlock.Header>
<CodeBlock.Content>
<CodeBlock.Code>
<CodeBlock.CodeText />
</CodeBlock.Code>
</CodeBlock.Content>
</CodeBlock.Root>
</CodeBlock.AdapterProvider>
适配器
¥Adapters
CodeBlock 组件适用于 Shiki 和 Highlight.js 高亮引擎。
¥The CodeBlock component works for Shiki and Highlight.js highlighting engines.
文档默认使用 Shiki。
要设置代码块组件,你需要:
¥To setup the code block component, you need to:
-
配置你首选的适配器(Shiki 或 Highlight.js)。
-
在顶层提供
CodeBlock.AdapterProvider
的适配器。 -
在
CodeBlock.AdapterProvider
中渲染CodeBlock.Root
组件。
Shiki
安装 shiki
软件包。
¥Install the shiki
package.
npm install shiki
然后,创建用于动态加载所选语言的 shiki 高亮器的 shiki 适配器。
¥Then, create the shiki adapter that dynamically loads the shiki highlighter for the selected languages.
import type { HighlighterGeneric } from "shiki"
import { createShikiAdapter } from "@chakra-ui/react"
const shikiAdapter = createShikiAdapter<HighlighterGeneric<any, any>>({
async load() {
const { createHighlighter } = await import("shiki")
return createHighlighter({
langs: ["tsx", "json"],
themes: ["github-dark", "github-light"],
})
},
})
<CodeBlock.AdapterProvider value={shikiAdapter}>
{/* ... */}
</CodeBlock.AdapterProvider>
Highlight.js
安装 highlight.js
软件包。
¥Install the highlight.js
package.
npm install highlight.js
然后,创建用于动态加载所选语言的 hightlight.js 适配器。
¥Then, create the highlight.js adapter that dynamically loads the selected languages.
import { createHighlightJsAdapter } from "@chakra-ui/react"
import hljs from "highlight.js/lib/core"
const highlightJsAdapter = createHighlightJsAdapter<typeof hljs>({
async load() {
const languages = {
tsx: () => import("highlight.js/lib/languages/typescript"),
html: () => import("highlight.js/lib/languages/xml"),
}
await Promise.all(
Object.entries(languages).map(async ([language, file]) => {
const { default: langModule } = await file()
hljs.registerLanguage(language, langModule)
}),
)
return hljs
},
})
示例
¥Examples
尺寸
¥Sizes
使用 size
属性更改代码块组件的大小。
¥Use the size
prop to change the size of the code block component.
<div class="container">
<h1>Hello, world!</h1>
</div>
<div class="container">
<h1>Hello, world!</h1>
</div>
<div class="container">
<h1>Hello, world!</h1>
</div>
"use client"
import { CodeBlock, For, Stack, createShikiAdapter } from "@chakra-ui/react"
import type { HighlighterGeneric } from "shiki"
const file = {
code: `
<div class="container">
<h1>Hello, world!</h1>
</div>
`,
language: "html",
title: "index.html",
}
const Demo = () => {
return (
<CodeBlock.AdapterProvider value={shikiAdapter}>
<Stack gap="8">
<For each={["sm", "md", "lg"]}>
{(size) => (
<CodeBlock.Root
key={size}
code={file.code}
language={file.language}
size={size}
>
<CodeBlock.Header>
<CodeBlock.Title>(size={size})</CodeBlock.Title>
</CodeBlock.Header>
<CodeBlock.Content>
<CodeBlock.Code>
<CodeBlock.CodeText />
</CodeBlock.Code>
</CodeBlock.Content>
</CodeBlock.Root>
)}
</For>
</Stack>
</CodeBlock.AdapterProvider>
)
}
const shikiAdapter = createShikiAdapter<HighlighterGeneric<any, any>>({
async load() {
const { createHighlighter } = await import("shiki")
return createHighlighter({
langs: ["tsx", "scss", "html", "bash", "json"],
themes: ["github-dark"],
})
},
theme: "github-dark",
})
标题
¥Title
在 CodeBlock.Header
组件中渲染 CodeBlock.Title
组件,为代码块组件添加标题。
¥Render the CodeBlock.Title
component within the CodeBlock.Header
component
to add a title to the code block component.
<div class="container">
<h1>Hello, world!</h1>
</div>
"use client"
import { CodeBlock, Icon, createShikiAdapter } from "@chakra-ui/react"
import { FaHtml5 } from "react-icons/fa"
import type { HighlighterGeneric } from "shiki"
const file = {
code: `
<div class="container">
<h1>Hello, world!</h1>
</div>
`,
language: "html",
title: "index.html",
}
const Demo = () => {
return (
<CodeBlock.AdapterProvider value={shikiAdapter}>
<CodeBlock.Root code={file.code} language={file.language}>
<CodeBlock.Header>
<CodeBlock.Title>
<Icon as={FaHtml5} color="orange.300" />
{file.title}
</CodeBlock.Title>
</CodeBlock.Header>
<CodeBlock.Content>
<CodeBlock.Code>
<CodeBlock.CodeText />
</CodeBlock.Code>
</CodeBlock.Content>
</CodeBlock.Root>
</CodeBlock.AdapterProvider>
)
}
const shikiAdapter = createShikiAdapter<HighlighterGeneric<any, any>>({
async load() {
const { createHighlighter } = await import("shiki")
return createHighlighter({
langs: ["tsx", "scss", "html", "bash", "json"],
themes: ["github-dark"],
})
},
theme: "github-dark",
})
复制按钮
¥Copy button
使用 copyButton
属性向代码块组件添加复制按钮。
¥Use the copyButton
prop to add a copy button to the code block component.
<div class="container">
<h1>Hello, world!</h1>
</div>
"use client"
import { CodeBlock, IconButton, createShikiAdapter } from "@chakra-ui/react"
import type { HighlighterGeneric } from "shiki"
const file = {
code: `
<div class="container">
<h1>Hello, world!</h1>
</div>
`,
language: "html",
title: "index.html",
}
const Demo = () => {
return (
<CodeBlock.AdapterProvider value={shikiAdapter}>
<CodeBlock.Root code={file.code} language={file.language}>
<CodeBlock.Header>
<CodeBlock.Title>{file.title}</CodeBlock.Title>
<CodeBlock.CopyTrigger asChild>
<IconButton variant="ghost" size="2xs">
<CodeBlock.CopyIndicator />
</IconButton>
</CodeBlock.CopyTrigger>
</CodeBlock.Header>
<CodeBlock.Content>
<CodeBlock.Code>
<CodeBlock.CodeText />
</CodeBlock.Code>
</CodeBlock.Content>
</CodeBlock.Root>
</CodeBlock.AdapterProvider>
)
}
const shikiAdapter = createShikiAdapter<HighlighterGeneric<any, any>>({
async load() {
const { createHighlighter } = await import("shiki")
return createHighlighter({
langs: ["tsx", "scss", "html", "bash", "json"],
themes: ["github-dark"],
})
},
theme: "github-dark",
})
行号
¥Line numbers
行号使引用特定代码行更加容易。传递 meta.showLineNumbers
属性以在代码块组件中显示行号。
¥Line numbers make it easier to reference specific lines of code. Pass the
meta.showLineNumbers
prop to show line numbers in the code block component.
<div class="container">
<h1>Hello, world!</h1>
</div>
"use client"
import { CodeBlock, createShikiAdapter } from "@chakra-ui/react"
import type { HighlighterGeneric } from "shiki"
const file = {
code: `
<div class="container">
<h1>Hello, world!</h1>
</div>
`,
language: "html",
title: "index.html",
}
const Demo = () => {
return (
<CodeBlock.AdapterProvider value={shikiAdapter}>
<CodeBlock.Root
code={file.code}
language={file.language}
meta={{ showLineNumbers: true }}
>
<CodeBlock.Content>
<CodeBlock.Code>
<CodeBlock.CodeText />
</CodeBlock.Code>
</CodeBlock.Content>
</CodeBlock.Root>
</CodeBlock.AdapterProvider>
)
}
const shikiAdapter = createShikiAdapter<HighlighterGeneric<any, any>>({
async load() {
const { createHighlighter } = await import("shiki")
return createHighlighter({
langs: ["tsx", "scss", "html", "bash", "json"],
themes: ["github-dark"],
})
},
theme: "github-dark",
})
线条高亮
¥Line highlighting
将 meta.highlightLines
属性传递给 CodeBlock.Root
组件,以高亮显示特定代码行。该属性接受一个行号数组。
¥Pass the meta.highlightLines
prop to the CodeBlock.Root
component to
highlight specific lines of code. The prop accepts an array of line numbers.
<div class="container">
<h1>Hello, world!</h1>
</div>
"use client"
import { CodeBlock, createShikiAdapter } from "@chakra-ui/react"
import type { HighlighterGeneric } from "shiki"
const file = {
code: `
<div class="container">
<h1>Hello, world!</h1>
</div>
`,
language: "html",
title: "index.html",
}
const Demo = () => {
return (
<CodeBlock.AdapterProvider value={shikiAdapter}>
<CodeBlock.Root
code={file.code}
language={file.language}
meta={{ highlightLines: [2, 1] }}
>
<CodeBlock.Content>
<CodeBlock.Code>
<CodeBlock.CodeText />
</CodeBlock.Code>
</CodeBlock.Content>
</CodeBlock.Root>
</CodeBlock.AdapterProvider>
)
}
const shikiAdapter = createShikiAdapter<HighlighterGeneric<any, any>>({
async load() {
const { createHighlighter } = await import("shiki")
return createHighlighter({
langs: ["tsx", "scss", "html", "bash", "json"],
themes: ["github-dark"],
})
},
theme: "github-dark",
})
线条焦点
¥Line focus
将 meta.highlightLines
属性传递给 CodeBlock.Root
组件,以高亮显示特定代码行。该属性接受一个行号数组。行号从 1 开始。
¥Pass the meta.highlightLines
prop to the CodeBlock.Root
component to
highlight specific lines of code. The prop accepts an array of line numbers. The
line numbers are 1-based.
const greeting = "Hello, World!"
function sayHello() {
console.log(greeting);
}
sayHello()
"use client"
import { CodeBlock, createShikiAdapter } from "@chakra-ui/react"
import type { HighlighterGeneric } from "shiki"
const file = {
code: `
const greeting = "Hello, World!"
function sayHello() {
console.log(greeting);
}
sayHello()
`,
language: "tsx",
title: "index.tsx",
}
const Demo = () => {
return (
<CodeBlock.AdapterProvider value={shikiAdapter}>
<CodeBlock.Root
code={file.code}
language={file.language}
meta={{ focusedLineNumbers: [3, 7] }}
>
<CodeBlock.Content>
<CodeBlock.Code>
<CodeBlock.CodeText />
</CodeBlock.Code>
</CodeBlock.Content>
</CodeBlock.Root>
</CodeBlock.AdapterProvider>
)
}
const shikiAdapter = createShikiAdapter<HighlighterGeneric<any, any>>({
async load() {
const { createHighlighter } = await import("shiki")
return createHighlighter({
langs: ["tsx", "scss", "html", "bash", "json"],
themes: ["github-dark"],
})
},
theme: "github-dark",
})
差异
¥Diff
差异有助于高亮源代码更改。使用 meta.addedLineNumbers
和 meta.removedLineNumbers
属性为代码块组件添加行号。
¥Diffs are useful for highlighting source code changes. Use the
meta.addedLineNumbers
and meta.removedLineNumbers
props to add line numbers
to the code block component.
该属性接受一个行号数组。行号从 1 开始。
const greeting = "Hello, World!";
function sayHello() {
console.log("Hello, World!");
console.log(greeting);
}
sayHello();
"use client"
import { CodeBlock, createShikiAdapter } from "@chakra-ui/react"
import type { HighlighterGeneric } from "shiki"
const file = {
code: `
const greeting = "Hello, World!";
function sayHello() {
console.log("Hello, World!");
console.log(greeting);
}
sayHello();
`,
language: "tsx",
title: "index.tsx",
}
const Demo = () => {
return (
<CodeBlock.AdapterProvider value={shikiAdapter}>
<CodeBlock.Root
code={file.code}
language={file.language}
meta={{
showLineNumbers: true,
addedLineNumbers: [1, 4],
removedLineNumbers: [3],
}}
>
<CodeBlock.Content>
<CodeBlock.Code>
<CodeBlock.CodeText />
</CodeBlock.Code>
</CodeBlock.Content>
</CodeBlock.Root>
</CodeBlock.AdapterProvider>
)
}
const shikiAdapter = createShikiAdapter<HighlighterGeneric<any, any>>({
async load() {
const { createHighlighter } = await import("shiki")
return createHighlighter({
langs: ["tsx", "scss", "html", "bash", "json"],
themes: ["github-dark"],
})
},
theme: "github-dark",
})
最大行数
¥Max lines
使用 meta.maxLines
属性限制代码块组件中的行数。默认情况下,代码块组件将扩展以适应内容。
¥Use the meta.maxLines
prop to limit the number of lines in the code block
component. By default, the code block component will expand to fit the content.
import * as React from 'react';
import { CodeBlock } from '@chakra-ui/react';
const Example = () => {
const code = `
{
"name": "My App",
"version": "1.0.0",
"description": "A simple web application",
"main": "index.js",
"scripts": {
"start": "node server.js",
"dev": "nodemon server.js",
"build": "webpack --mode production",
"test": "jest"
},
"dependencies": {
"express": "^4.18.2",
"react": "^18.2.0",
"axios": "^1.4.0"
},
"author": "Developer",
"license": "MIT"
}
`
return (
<CodeBlock.Root language="json" code={code}>
<CodeBlock.Header>
<CodeBlock.Title>{file.title}</CodeBlock.Title>
</CodeBlock.Header>
</CodeBlock.Root>
);
};
export default Example;
"use client"
import { CodeBlock, IconButton, createShikiAdapter } from "@chakra-ui/react"
import type { HighlighterGeneric } from "shiki"
const Demo = () => {
return (
<CodeBlock.AdapterProvider value={shikiAdapter}>
<CodeBlock.Root code={file.code} language={file.language} maxLines={10}>
<CodeBlock.Header>
<CodeBlock.Title>{file.title}</CodeBlock.Title>
<CodeBlock.Control>
<CodeBlock.CollapseTrigger asChild>
<IconButton variant="ghost" size="2xs">
<CodeBlock.CollapseIndicator />
</IconButton>
</CodeBlock.CollapseTrigger>
<CodeBlock.CopyTrigger asChild>
<IconButton variant="ghost" size="2xs">
<CodeBlock.CopyIndicator />
</IconButton>
</CodeBlock.CopyTrigger>
</CodeBlock.Control>
</CodeBlock.Header>
<CodeBlock.Content>
<CodeBlock.Code>
<CodeBlock.CodeText />
</CodeBlock.Code>
<CodeBlock.Overlay>
<CodeBlock.CollapseTrigger>
<CodeBlock.CollapseText textStyle="sm" />
</CodeBlock.CollapseTrigger>
</CodeBlock.Overlay>
</CodeBlock.Content>
</CodeBlock.Root>
</CodeBlock.AdapterProvider>
)
}
const shikiAdapter = createShikiAdapter<HighlighterGeneric<any, any>>({
async load() {
const { createHighlighter } = await import("shiki")
return createHighlighter({
langs: ["tsx", "scss", "html", "bash", "json"],
themes: ["github-dark"],
})
},
theme: "github-dark",
})
const file = {
code: `import * as React from 'react';
import { CodeBlock } from '@chakra-ui/react';
const Example = () => {
const code = \`
{
"name": "My App",
"version": "1.0.0",
"description": "A simple web application",
"main": "index.js",
"scripts": {
"start": "node server.js",
"dev": "nodemon server.js",
"build": "webpack --mode production",
"test": "jest"
},
"dependencies": {
"express": "^4.18.2",
"react": "^18.2.0",
"axios": "^1.4.0"
},
"author": "Developer",
"license": "MIT"
}
\`
return (
<CodeBlock.Root language="json" code={code}>
<CodeBlock.Header>
<CodeBlock.Title>{file.title}</CodeBlock.Title>
</CodeBlock.Header>
</CodeBlock.Root>
);
};
export default Example;
`,
language: "tsx",
title: "index.tsx",
}
语言切换器
¥Language switcher
这是一个通过组合 CodeBlock
和 Select
组件重新创建 API 端点请求组件的示例。
¥Here's an example that re-creates an API endpoint request component by composing
the CodeBlock
and Select
components.
from github import Github
# Create a Github instance using an access token
g = Github("YOUR_ACCESS_TOKEN")
# Get a repository
repo = g.get_repo("octocat/Hello-World")
# Get repository information
print(f"Repository: {repo.name}")
print(f"Description: {repo.description}")
print(f"Stars: {repo.stargazers_count}")
# List issues
issues = repo.get_issues(state='open')
for issue in issues:
print(f"Issue #{issue.number}: {issue.title}")
"use client"
import {
Badge,
CodeBlock,
HStack,
Icon,
IconButton,
Select,
Span,
createListCollection,
createShikiAdapter,
useSelect,
} from "@chakra-ui/react"
import { IoLogoJavascript, IoLogoPython } from "react-icons/io5"
import type { HighlighterGeneric } from "shiki"
const Demo = () => {
const select = useSelect({
positioning: { strategy: "fixed" },
defaultValue: [files[0].value],
collection,
})
const selectedFile = select.selectedItems[0]
return (
<CodeBlock.AdapterProvider value={shikiAdapter}>
<CodeBlock.Root
code={selectedFile.code}
language={selectedFile.language}
size="lg"
>
<CodeBlock.Header>
<HStack flex="1">
<Badge colorPalette="teal" fontWeight="bold">
POST
</Badge>
<Span textStyle="xs">/v1/search</Span>
</HStack>
<CodeBlock.Control>
<LanguageSwitcher value={select} />
<CodeBlock.CopyTrigger asChild>
<IconButton variant="ghost" size="2xs">
<CodeBlock.CopyIndicator />
</IconButton>
</CodeBlock.CopyTrigger>
</CodeBlock.Control>
</CodeBlock.Header>
<CodeBlock.Content>
<CodeBlock.Code fontSize="xs">
<CodeBlock.CodeText />
</CodeBlock.Code>
</CodeBlock.Content>
</CodeBlock.Root>
</CodeBlock.AdapterProvider>
)
}
function LanguageSwitcher(props: Select.RootProviderProps) {
const { value: select } = props
return (
<Select.RootProvider size="xs" variant="subtle" {...props}>
<Select.Control>
<Select.Trigger>
<Select.ValueText />
<Select.Indicator />
</Select.Trigger>
</Select.Control>
<Select.Positioner>
<Select.Content>
{select.collection.items.map((item) => (
<Select.Item item={item} key={item.value}>
{item.icon}
<Select.ItemText>{item.value}</Select.ItemText>
</Select.Item>
))}
</Select.Content>
</Select.Positioner>
</Select.RootProvider>
)
}
const shikiAdapter = createShikiAdapter<HighlighterGeneric<any, any>>({
async load() {
const { createHighlighter } = await import("shiki")
return createHighlighter({
langs: ["python", "typescript"],
themes: ["github-dark"],
})
},
theme: "github-dark",
})
interface CodeFile {
value: string
code: string
language: string
title: string
icon: React.ReactElement
}
const files: CodeFile[] = [
{
value: "python",
code: `
from github import Github
# Create a Github instance using an access token
g = Github("YOUR_ACCESS_TOKEN")
# Get a repository
repo = g.get_repo("octocat/Hello-World")
# Get repository information
print(f"Repository: {repo.name}")
print(f"Description: {repo.description}")
print(f"Stars: {repo.stargazers_count}")
# List issues
issues = repo.get_issues(state='open')
for issue in issues:
print(f"Issue #{issue.number}: {issue.title}")
`,
language: "python",
title: "python.py",
icon: <Icon as={IoLogoPython} size="xs" color="orange.500" />,
},
{
value: "typescript",
code: `
import { Octokit } from "@octokit/rest";
// Create an Octokit instance
const octokit = new Octokit({
auth: "YOUR_ACCESS_TOKEN",
});
// Get repository information
const { data: repo } = await octokit.rest.repos.get({
owner: "octocat",
repo: "Hello-World",
});
console.log(\`Repository: \${repo.name}\`);
console.log(\`Description: \${repo.description}\`);
console.log(\`Stars: \${repo.stargazers_count}\`);
// List issues
const { data: issues } = await octokit.rest.issues.listForRepo({
owner: "octocat",
repo: "Hello-World",
state: "open",
});
issues.forEach((issue) => {
console.log(\`Issue #\${issue.number}: \${issue.title}\`);
});
`,
language: "typescript",
title: "typescript.ts",
icon: <Icon as={IoLogoJavascript} size="xs" color="blue.500" />,
},
]
const collection = createListCollection({
items: files,
itemToString: (item) => item.value,
itemToValue: (item) => item.value,
})
浮动复制按钮
¥Floating copy button
以下是向代码块组件添加浮动复制按钮的示例。
¥Here's an example that adds a floating copy button to the code block component.
<div class="container">
<h1>Hello, world!</h1>
</div>
"use client"
import {
CodeBlock,
Float,
IconButton,
createShikiAdapter,
} from "@chakra-ui/react"
import type { HighlighterGeneric } from "shiki"
const file = {
code: `
<div class="container">
<h1>Hello, world!</h1>
</div>
`,
language: "html",
title: "index.html",
}
const Demo = () => {
return (
<CodeBlock.AdapterProvider value={shikiAdapter}>
<CodeBlock.Root code={file.code} language={file.language}>
<CodeBlock.Content>
<Float placement="top-end" offset="5" zIndex="1">
<CodeBlock.CopyTrigger asChild>
<IconButton variant="ghost" size="2xs">
<CodeBlock.CopyIndicator />
</IconButton>
</CodeBlock.CopyTrigger>
</Float>
<CodeBlock.Code>
<CodeBlock.CodeText />
</CodeBlock.Code>
</CodeBlock.Content>
</CodeBlock.Root>
</CodeBlock.AdapterProvider>
)
}
const shikiAdapter = createShikiAdapter<HighlighterGeneric<any, any>>({
async load() {
const { createHighlighter } = await import("shiki")
return createHighlighter({
langs: ["tsx", "scss", "html", "bash", "json"],
themes: ["github-dark"],
})
},
theme: "github-dark",
})
标签
¥Tabs
以下是将 CodeBlock
组件与 Tabs
组件组合以创建带有标签的代码块的示例。
¥Here's an example that composes the CodeBlock
component with the Tabs
component to create a code block with tabs.
print('Hello, World!')
"use client"
import {
CodeBlock,
IconButton,
Tabs,
createShikiAdapter,
useTabs,
} from "@chakra-ui/react"
import type { HighlighterGeneric } from "shiki"
const Demo = () => {
const tabs = useTabs({
defaultValue: "python",
})
const activeTab =
files.find((file) => file.language === tabs.value) || files[0]
const otherTabs = files.filter((file) => file.language !== tabs.value)
return (
<CodeBlock.AdapterProvider value={shikiAdapter}>
<Tabs.RootProvider value={tabs} size="sm" variant="line">
<CodeBlock.Root code={activeTab.code} language={activeTab.language}>
<CodeBlock.Header borderBottomWidth="1px">
<Tabs.List w="full" border="0" ms="-1">
{files.map((file) => (
<Tabs.Trigger
colorPalette="teal"
key={file.language}
value={file.language}
textStyle="xs"
>
{file.title}
</Tabs.Trigger>
))}
</Tabs.List>
<CodeBlock.CopyTrigger asChild>
<IconButton variant="ghost" size="2xs">
<CodeBlock.CopyIndicator />
</IconButton>
</CodeBlock.CopyTrigger>
</CodeBlock.Header>
<CodeBlock.Content>
{otherTabs.map((file) => (
<Tabs.Content key={file.language} value={file.language} />
))}
<Tabs.Content pt="1" value={activeTab.language}>
<CodeBlock.Code>
<CodeBlock.CodeText />
</CodeBlock.Code>
</Tabs.Content>
</CodeBlock.Content>
</CodeBlock.Root>
</Tabs.RootProvider>
</CodeBlock.AdapterProvider>
)
}
const shikiAdapter = createShikiAdapter<HighlighterGeneric<any, any>>({
async load() {
const { createHighlighter } = await import("shiki")
return createHighlighter({
langs: ["python", "typescript", "java"],
themes: ["github-dark"],
})
},
theme: "github-dark",
})
const files = [
{ title: "Python", language: "python", code: "print('Hello, World!')" },
{
title: "TypeScript",
language: "typescript",
code: "console.log('Hello, World!')",
},
{
title: "Java",
language: "java",
code: "System.out.println('Hello, World!');",
},
]
标签同步
¥Tabs sync
以下是自动同步所有共享相同存储键的代码块的示例。用于文档站点中的包管理器或框架特定的代码块。
¥Here's an example that automatically syncs all code blocks that share the same storage key. Useful for package manager or framework specific code blocks in a documentation site.
npm install @chakra-ui/react
npm install @chakra-ui/react
"use client"
import {
CodeBlock,
IconButton,
Stack,
Tabs,
createShikiAdapter,
useTabs,
} from "@chakra-ui/react"
import { useEffect } from "react"
import type { HighlighterGeneric } from "shiki"
const files = [
{ title: "npm", language: "bash", code: "npm install @chakra-ui/react" },
{
title: "yarn",
language: "bash",
code: "yarn add @chakra-ui/react",
},
{
title: "bun",
language: "bash",
code: "bun install @chakra-ui/react",
},
]
const Demo = () => {
return (
<CodeBlock.AdapterProvider value={shikiAdapter}>
<Stack gap="8">
<CodeTabs />
<CodeTabs />
</Stack>
</CodeBlock.AdapterProvider>
)
}
const shikiAdapter = createShikiAdapter<HighlighterGeneric<any, any>>({
async load() {
const { createHighlighter } = await import("shiki")
return createHighlighter({
langs: ["bash"],
themes: ["github-dark"],
})
},
theme: "github-dark",
})
const CodeTabs = () => {
const tabs = useTabsSync({
defaultValue: files[0].title,
storageKey: "code-tabs-sync",
})
const activeTab = files.find((file) => file.title === tabs.value) || files[0]
const otherTabs = files.filter((file) => file.title !== tabs.value)
return (
<Tabs.RootProvider value={tabs} size="sm" variant="line">
<CodeBlock.Root code={activeTab.code} language={activeTab.language}>
<CodeBlock.Header borderBottomWidth="1px">
<Tabs.List w="full" border="0" ms="-1">
{files.map((file) => (
<Tabs.Trigger
colorPalette="teal"
key={file.title}
value={file.title}
textStyle="xs"
>
{file.title}
</Tabs.Trigger>
))}
</Tabs.List>
<CodeBlock.CopyTrigger asChild>
<IconButton variant="ghost" size="2xs">
<CodeBlock.CopyIndicator />
</IconButton>
</CodeBlock.CopyTrigger>
</CodeBlock.Header>
<CodeBlock.Content>
{otherTabs.map((file) => (
<Tabs.Content key={file.title} value={file.title} />
))}
<Tabs.Content pt="1" value={activeTab.title}>
<CodeBlock.Code>
<CodeBlock.CodeText />
</CodeBlock.Code>
</Tabs.Content>
</CodeBlock.Content>
</CodeBlock.Root>
</Tabs.RootProvider>
)
}
function useTabsSync(props: { defaultValue: string; storageKey: string }) {
const { defaultValue, storageKey } = props
const tabs = useTabs({
defaultValue,
onValueChange(details) {
if (details.value) {
localStorage.setItem(storageKey, details.value)
dispatchEvent(
new StorageEvent("storage", {
key: storageKey,
newValue: details.value,
}),
)
}
},
})
useEffect(() => {
const handleStorageChange = (e: StorageEvent) => {
requestAnimationFrame(() => {
if (e.key === storageKey && e.newValue) {
tabs.setValue(e.newValue)
}
})
}
window.addEventListener("storage", handleStorageChange)
return () => window.removeEventListener("storage", handleStorageChange)
}, [storageKey, tabs])
return tabs
}
主题
¥Themes
使用 meta.colorScheme
属性为代码块组件添加主题。在此示例中,colorScheme 已从 useColorMode
钩子设置为颜色模式。
¥Use the meta.colorScheme
prop to add a theme to the code block component. In
this example, the colorScheme is set to color mode from the useColorMode
hook.
"use client"
import { ClientOnly, CodeBlock, createShikiAdapter } from "@chakra-ui/react"
import { useColorMode } from "@/components/ui/color-mode"
import type { HighlighterGeneric } from "shiki"
const file = {
code: `
<div class="container">
<h1>Hello, world!</h1>
</div>
`,
language: "html",
title: "index.html",
}
const Demo = () => {
const { colorMode } = useColorMode()
return (
<CodeBlock.AdapterProvider value={shikiAdapter}>
<ClientOnly fallback={<div>Loading...</div>}>
{() => (
<CodeBlock.Root
code={file.code}
language={file.language}
meta={{ colorScheme: colorMode }}
>
<CodeBlock.Content bg="bg">
<CodeBlock.Code>
<CodeBlock.CodeText />
</CodeBlock.Code>
</CodeBlock.Content>
</CodeBlock.Root>
)}
</ClientOnly>
</CodeBlock.AdapterProvider>
)
}
const shikiAdapter = createShikiAdapter<HighlighterGeneric<any, any>>({
async load() {
const { createHighlighter } = await import("shiki")
return createHighlighter({
langs: ["tsx", "scss", "html", "bash", "json"],
themes: ["github-dark", "github-light"],
})
},
theme: {
light: "github-light",
dark: "github-dark",
},
})
溢出换行
¥Wrap overflow
使用 meta.wordWrap
属性封装代码块组件。
¥Use the meta.wordWrap
prop to wrap the code block component.
const greeting = "Hello, World! I am a long line of text that will wrap to the next line."
function sayHello() {
console.log(greeting)
}
sayHello()
"use client"
import { CodeBlock, IconButton, createShikiAdapter } from "@chakra-ui/react"
import type { HighlighterGeneric } from "shiki"
const file = {
code: `
const greeting = "Hello, World! I am a long line of text that will wrap to the next line."
function sayHello() {
console.log(greeting)
}
sayHello()
`,
language: "tsx",
title: "index.tsx",
}
const Demo = () => {
return (
<CodeBlock.AdapterProvider value={shikiAdapter}>
<CodeBlock.Root
maxW="md"
code={file.code}
language={file.language}
meta={{ wordWrap: true }}
>
<CodeBlock.Header>
<CodeBlock.Title>{file.title}</CodeBlock.Title>
<CodeBlock.CopyTrigger asChild>
<IconButton variant="ghost" size="2xs">
<CodeBlock.CopyIndicator />
</IconButton>
</CodeBlock.CopyTrigger>
</CodeBlock.Header>
<CodeBlock.Content>
<CodeBlock.Code>
<CodeBlock.CodeText />
</CodeBlock.Code>
</CodeBlock.Content>
</CodeBlock.Root>
</CodeBlock.AdapterProvider>
)
}
const shikiAdapter = createShikiAdapter<HighlighterGeneric<any, any>>({
async load() {
const { createHighlighter } = await import("shiki")
return createHighlighter({
langs: ["tsx", "scss", "html", "bash", "json"],
themes: ["github-dark"],
})
},
theme: "github-dark",
})
Highlight.js
这是一个使用 hightlight.js 高亮代码块的示例。
¥Here's an example that uses highlight.js to highlight the code block.
<div class="container">
<h1>Hello, world!</h1>
</div>
"use client"
import { CodeBlock, createHighlightJsAdapter } from "@chakra-ui/react"
import hljs from "highlight.js/lib/core"
const file = {
code: `
<div class="container">
<h1>Hello, world!</h1>
</div>
`,
language: "html",
title: "index.html",
}
const Demo = () => {
return (
<CodeBlock.AdapterProvider value={highlightJsAdapter}>
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github-dark.min.css"
/>
<CodeBlock.Root code={file.code} language={file.language}>
<CodeBlock.Header>
<CodeBlock.Title>{file.title}</CodeBlock.Title>
</CodeBlock.Header>
<CodeBlock.Content>
<CodeBlock.Code>
<CodeBlock.CodeText />
</CodeBlock.Code>
</CodeBlock.Content>
</CodeBlock.Root>
</CodeBlock.AdapterProvider>
)
}
const highlightJsAdapter = createHighlightJsAdapter<typeof hljs>({
async load() {
const languages = {
tsx: () => import("highlight.js/lib/languages/typescript"),
html: () => import("highlight.js/lib/languages/xml"),
}
await Promise.all(
Object.entries(languages).map(async ([language, file]) => {
const { default: langModule } = await file()
hljs.registerLanguage(language, langModule)
}),
)
return hljs
},
})
纯文本
¥Plain text
代码块默认使用纯文本。要创建纯文本代码块,请删除 CodeBlock.AdapterProvider
属性。
¥The code block falls back to a plain text by default. To create a plain text
code block, remove the use of CodeBlock.AdapterProvider
.
$npm install @chakra-ui/react
"use client"
import { CodeBlock, Float, IconButton, Span } from "@chakra-ui/react"
const file = {
code: "npm install @chakra-ui/react",
language: "bash",
title: "npm install @chakra-ui/react",
}
const Demo = () => {
return (
<CodeBlock.Root
code={file.code}
language={file.language}
display="inline-flex"
>
<CodeBlock.Content>
<Float placement="middle-end" offsetX="6" zIndex="1">
<CodeBlock.CopyTrigger asChild>
<IconButton variant="ghost" size="2xs">
<CodeBlock.CopyIndicator />
</IconButton>
</CodeBlock.CopyTrigger>
</Float>
<CodeBlock.Code pe="10">
<Span color="fg.muted" ms="4" userSelect="none">
$
</Span>
<CodeBlock.CodeText display="inline-block" />
</CodeBlock.Code>
</CodeBlock.Content>
</CodeBlock.Root>
)
}
属性
¥Props
Prop | Default | Type |
---|---|---|
colorPalette | 'gray' | 'gray' | 'red' | 'orange' | 'yellow' | 'green' | 'teal' | 'blue' | 'cyan' | 'purple' | 'pink' The color palette of the component |
variant | 'subtle' | 'solid' | 'subtle' | 'outline' | 'surface' | 'plain' The variant of the component |
size | 'sm' | 'xs' | 'sm' | 'md' | 'lg' The size of the component |
as | React.ElementType The underlying element to render. | |
asChild | boolean Use the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. |