CodeHighlighted 代码高亮
@lark-ui/core

v1.10 新增: 基于 Shiki 的语法高亮,支持懒加载。从 @lark-ui/core/code 导入即可使用。

const greeting = "Hello, World!";
console.log(greeting);
import { ShikiProvider, CodeHighlighted } from "@lark-ui/core/code";
import { ReactNode } from "react";

/**
 * Wrapper component that provides Shiki context for all demos.
 * This loads Shiki once and shares it across all CodeHighlighted instances.
 */
function DemoProvider({ children }: { children: ReactNode }) {
  return (
    <ShikiProvider
      engine="javascript"
      languages={[
        "tsx",
        "typescript",
        "javascript",
        "bash",
        "json",
        "css",
        "html",
      ]}
    >
      {children}
    </ShikiProvider>
  );
}

/** 基础代码高亮(CodeHighlighted)示例 */
export function CodeHighlightedBasicDemo() {
  return (
    <DemoProvider>
      <CodeHighlighted
        code={`const greeting = "Hello, World!";
console.log(greeting);`}
        lang="typescript"
      />
    </DemoProvider>
  );
}

概览

基于 Shiki 的语法高亮器。借助 TextMate 语法支持 200 多种语言,提供浅色/深色双主题,并支持懒加载。通过独立入口(@lark-ui/core/code)导出,避免为不需要它的应用打包 Shiki。

安装

CodeHighlighted 通过独立入口导出,以避免为不需要它的应用打包 Shiki。

import { ShikiProvider, CodeHighlighted } from "@lark-ui/core/code";

重要: 请勿从主入口 @lark-ui/core 导入。否则即便不使用, 也会把 Shiki 打进你的产物包。

基本用法

用 ShikiProvider 包裹应用,只需配置一次 Shiki。 其内部所有 CodeHighlighted 组件将共享同一个 Shiki 实例。

import { ShikiProvider, CodeHighlighted } from "@lark-ui/core/code";

export function App() {
  return (
    <ShikiProvider
      engine="javascript"
      languages={["tsx", "typescript", "bash", "json"]}
    >
      {/* All CodeHighlighted components share the same Shiki instance */}
      <CodeHighlighted code="const x = 1;" lang="typescript" />
    </ShikiProvider>
  );
}

示例

语言

CodeHighlighted 通过 Shiki 支持 200 多种语言。请只加载你需要的语言。

TypeScript

interface User {
  id: string;
  name: string;
  email: string;
}

async function fetchUser(id: string): Promise<User> {
  const response = await fetch(`/api/users/${id}`);
  return response.json();
}
import { ShikiProvider, CodeHighlighted } from "@lark-ui/core/code";
import { ReactNode } from "react";

/**
 * Wrapper component that provides Shiki context for all demos.
 * This loads Shiki once and shares it across all CodeHighlighted instances.
 */
function DemoProvider({ children }: { children: ReactNode }) {
  return (
    <ShikiProvider
      engine="javascript"
      languages={[
        "tsx",
        "typescript",
        "javascript",
        "bash",
        "json",
        "css",
        "html",
      ]}
    >
      {children}
    </ShikiProvider>
  );
}

/** 包含 interface 的 TypeScript 代码 */
export function CodeHighlightedTypeScriptDemo() {
  return (
    <DemoProvider>
      <CodeHighlighted
        code={`interface User {
  id: string;
  name: string;
  email: string;
}

async function fetchUser(id: string): Promise<User> {
  const response = await fetch(\`/api/users/\${id}\`);
  return response.json();
}`}
        lang="typescript"
      />
    </DemoProvider>
  );
}

React / TSX

import { useState } from "react";

export function Counter() {
  const [count, setCount] = useState(0);
  
  return (
    <button onClick={() => setCount(c => c + 1)}>
      Count: {count}
    </button>
  );
}
import { ShikiProvider, CodeHighlighted } from "@lark-ui/core/code";
import { ReactNode } from "react";

/**
 * Wrapper component that provides Shiki context for all demos.
 * This loads Shiki once and shares it across all CodeHighlighted instances.
 */
function DemoProvider({ children }: { children: ReactNode }) {
  return (
    <ShikiProvider
      engine="javascript"
      languages={[
        "tsx",
        "typescript",
        "javascript",
        "bash",
        "json",
        "css",
        "html",
      ]}
    >
      {children}
    </ShikiProvider>
  );
}

/** React/TSX 代码示例 */
export function CodeHighlightedReactDemo() {
  return (
    <DemoProvider>
      <CodeHighlighted
        code={`import { useState } from "react";

export function Counter() {
  const [count, setCount] = useState(0);
  
  return (
    <button onClick={() => setCount(c => c + 1)}>
      Count: {count}
    </button>
  );
}`}
        lang="tsx"
      />
    </DemoProvider>
  );
}

Bash / Shell

# Install Lark
npm install @lark-ui/core

# Or with pnpm
pnpm add @lark-ui/core

# Start development server
pnpm dev
import { ShikiProvider, CodeHighlighted } from "@lark-ui/core/code";
import { ReactNode } from "react";

/**
 * Wrapper component that provides Shiki context for all demos.
 * This loads Shiki once and shares it across all CodeHighlighted instances.
 */
function DemoProvider({ children }: { children: ReactNode }) {
  return (
    <ShikiProvider
      engine="javascript"
      languages={[
        "tsx",
        "typescript",
        "javascript",
        "bash",
        "json",
        "css",
        "html",
      ]}
    >
      {children}
    </ShikiProvider>
  );
}

/** Bash/shell 命令 */
export function CodeHighlightedBashDemo() {
  return (
    <DemoProvider>
      <CodeHighlighted
        code={`# Install Lark
npm install @lark-ui/core

# Or with pnpm
pnpm add @lark-ui/core

# Start development server
pnpm dev`}
        lang="bash"
      />
    </DemoProvider>
  );
}

JSON

{
  "name": "@lark-ui/core",
  "version": "1.9.0",
  "dependencies": {
    "react": "^19.0.0",
    "shiki": "^4.0.0"
  }
}
import { ShikiProvider, CodeHighlighted } from "@lark-ui/core/code";
import { ReactNode } from "react";

/**
 * Wrapper component that provides Shiki context for all demos.
 * This loads Shiki once and shares it across all CodeHighlighted instances.
 */
function DemoProvider({ children }: { children: ReactNode }) {
  return (
    <ShikiProvider
      engine="javascript"
      languages={[
        "tsx",
        "typescript",
        "javascript",
        "bash",
        "json",
        "css",
        "html",
      ]}
    >
      {children}
    </ShikiProvider>
  );
}

/** JSON 配置 */
export function CodeHighlightedJsonDemo() {
  return (
    <DemoProvider>
      <CodeHighlighted
        code={`{
  "name": "@lark-ui/core",
  "version": "1.9.0",
  "dependencies": {
    "react": "^19.0.0",
    "shiki": "^4.0.0"
  }
}`}
        lang="json"
      />
    </DemoProvider>
  );
}

CSS

.button {
  background: var(--color-brand);
  border-radius: 0.5rem;
  padding: 0.5rem 1rem;
  
  &:hover {
    background: var(--color-brand-hover);
  }
}
import { ShikiProvider, CodeHighlighted } from "@lark-ui/core/code";
import { ReactNode } from "react";

/**
 * Wrapper component that provides Shiki context for all demos.
 * This loads Shiki once and shares it across all CodeHighlighted instances.
 */
function DemoProvider({ children }: { children: ReactNode }) {
  return (
    <ShikiProvider
      engine="javascript"
      languages={[
        "tsx",
        "typescript",
        "javascript",
        "bash",
        "json",
        "css",
        "html",
      ]}
    >
      {children}
    </ShikiProvider>
  );
}

/** CSS 代码示例 */
export function CodeHighlightedCssDemo() {
  return (
    <DemoProvider>
      <CodeHighlighted
        code={`.button {
  background: var(--color-brand);
  border-radius: 0.5rem;
  padding: 0.5rem 1rem;
  
  &:hover {
    background: var(--color-brand-hover);
  }
}`}
        lang="css"
      />
    </DemoProvider>
  );
}

高亮行

使用 highlightLines(从 1 开始计数)突出显示指定的行。

function processData(items: string[]) {
  // Filter out empty items
  const filtered = items.filter(Boolean);
  
  // Transform to uppercase (highlighted)
  const transformed = filtered.map(item => item.toUpperCase());
  
  // Return sorted result
  return transformed.toSorted();
}
import { ShikiProvider, CodeHighlighted } from "@lark-ui/core/code";
import { ReactNode } from "react";

/**
 * Wrapper component that provides Shiki context for all demos.
 * This loads Shiki once and shares it across all CodeHighlighted instances.
 */
function DemoProvider({ children }: { children: ReactNode }) {
  return (
    <ShikiProvider
      engine="javascript"
      languages={[
        "tsx",
        "typescript",
        "javascript",
        "bash",
        "json",
        "css",
        "html",
      ]}
    >
      {children}
    </ShikiProvider>
  );
}

/** 高亮指定行 */
export function CodeHighlightedHighlightLinesDemo() {
  return (
    <DemoProvider>
      <CodeHighlighted
        code={`function processData(items: string[]) {
  // Filter out empty items
  const filtered = items.filter(Boolean);
  
  // Transform to uppercase (highlighted)
  const transformed = filtered.map(item => item.toUpperCase());
  
  // Return sorted result
  return transformed.toSorted();
}`}
        lang="typescript"
        highlightLines={[5, 6]}
      />
    </DemoProvider>
  );
}

自定义高亮颜色

通过 CSS 变量 --lark-code-highlight-bg 自定义高亮颜色。

function greet(name: string) {
  // This line is highlighted
  console.log(`Hello, ${name}!`);
  
  return name.toUpperCase();
}
CSS 变量--lark-code-highlight-bg: hsla(220, 80%, 50%, 0.1)

行号

使用 showLineNumbers 显示行号。

import { useState, useEffect } from "react";

export function useWindowSize() {
  const [size, setSize] = useState({ width: 0, height: 0 });
  
  useEffect(() => {
    function handleResize() {
      setSize({
        width: window.innerWidth,
        height: window.innerHeight,
      });
    }
    
    handleResize();
    window.addEventListener("resize", handleResize);
    return () => window.removeEventListener("resize", handleResize);
  }, []);
  
  return size;
}
import { ShikiProvider, CodeHighlighted } from "@lark-ui/core/code";
import { ReactNode } from "react";

/**
 * Wrapper component that provides Shiki context for all demos.
 * This loads Shiki once and shares it across all CodeHighlighted instances.
 */
function DemoProvider({ children }: { children: ReactNode }) {
  return (
    <ShikiProvider
      engine="javascript"
      languages={[
        "tsx",
        "typescript",
        "javascript",
        "bash",
        "json",
        "css",
        "html",
      ]}
    >
      {children}
    </ShikiProvider>
  );
}

/** 显示行号 */
export function CodeHighlightedLineNumbersDemo() {
  return (
    <DemoProvider>
      <CodeHighlighted
        code={`import { useState, useEffect } from "react";

export function useWindowSize() {
  const [size, setSize] = useState({ width: 0, height: 0 });
  
  useEffect(() => {
    function handleResize() {
      setSize({
        width: window.innerWidth,
        height: window.innerHeight,
      });
    }
    
    handleResize();
    window.addEventListener("resize", handleResize);
    return () => window.removeEventListener("resize", handleResize);
  }, []);
  
  return size;
}`}
        lang="typescript"
        showLineNumbers
      />
    </DemoProvider>
  );
}

复制按钮

使用 showCopyButton 添加复制到剪贴板的按钮。

npm install @lark-ui/core
import { ShikiProvider, CodeHighlighted } from "@lark-ui/core/code";
import { ReactNode } from "react";

/**
 * Wrapper component that provides Shiki context for all demos.
 * This loads Shiki once and shares it across all CodeHighlighted instances.
 */
function DemoProvider({ children }: { children: ReactNode }) {
  return (
    <ShikiProvider
      engine="javascript"
      languages={[
        "tsx",
        "typescript",
        "javascript",
        "bash",
        "json",
        "css",
        "html",
      ]}
    >
      {children}
    </ShikiProvider>
  );
}

/** 带复制按钮 */
export function CodeHighlightedCopyButtonDemo() {
  return (
    <DemoProvider>
      <CodeHighlighted
        code={`npm install @lark-ui/core`}
        lang="bash"
        showCopyButton
      />
    </DemoProvider>
  );
}

纯文本

在另一个容器内嵌入高亮代码时,使用 variant="plain" 可去掉外层表面、边框和圆角。

type EmbeddedOptions = {
  enabled: boolean;
  target: string;
};

const options = {
  enabled: true,
  target: "#preview",
} satisfies EmbeddedOptions;

console.log(options);
type EmbeddedOptions = {
  enabled: boolean;
  target: string;
};

const options = {
  enabled: true,
  target: "#preview",
} satisfies EmbeddedOptions;

console.log(options);
import { ShikiProvider, CodeHighlighted } from "@lark-ui/core/code";
import { ReactNode } from "react";

/**
 * Wrapper component that provides Shiki context for all demos.
 * This loads Shiki once and shares it across all CodeHighlighted instances.
 */
function DemoProvider({ children }: { children: ReactNode }) {
  return (
    <ShikiProvider
      engine="javascript"
      languages={[
        "tsx",
        "typescript",
        "javascript",
        "bash",
        "json",
        "css",
        "html",
      ]}
    >
      {children}
    </ShikiProvider>
  );
}

/** 无边框代码块,可嵌入到其他界面中 */
export function CodeHighlightedPlainDemo() {
  return (
    <DemoProvider>
      <div className="grid divide-x divide-lark-line rounded border border-lark-line md:grid-cols-2">
        <div className="p-2">
          <CodeHighlighted
            showLineNumbers
            code={`type EmbeddedOptions = {
  enabled: boolean;
  target: string;
};

const options = {
  enabled: true,
  target: "#preview",
} satisfies EmbeddedOptions;

console.log(options);`}
            lang="typescript"
            variant="plain"
          />
        </div>
        <div className="p-2">
          <CodeHighlighted
            showCopyButton
            code={`type EmbeddedOptions = {
  enabled: boolean;
  target: string;
};

const options = {
  enabled: true,
  target: "#preview",
} satisfies EmbeddedOptions;

console.log(options);`}
            lang="typescript"
            variant="plain"
            highlightLines={[6, 7, 8, 9]}
          />
        </div>
      </div>
    </DemoProvider>
  );
}

完整功能

组合全部功能,获得完整的代码展示体验。

import { ShikiProvider, CodeHighlighted } from "@lark-ui/core/code";

export function CodeExample({ code, language }: Props) {
  return (
    <ShikiProvider
      engine="javascript"
      languages={["tsx", "typescript", "bash", "json"]}
    >
      <CodeHighlighted
        code={code}
        lang={language}
        showCopyButton
      />
    </ShikiProvider>
  );
}
import { ShikiProvider, CodeHighlighted } from "@lark-ui/core/code";
import { ReactNode } from "react";

/**
 * Wrapper component that provides Shiki context for all demos.
 * This loads Shiki once and shares it across all CodeHighlighted instances.
 */
function DemoProvider({ children }: { children: ReactNode }) {
  return (
    <ShikiProvider
      engine="javascript"
      languages={[
        "tsx",
        "typescript",
        "javascript",
        "bash",
        "json",
        "css",
        "html",
      ]}
    >
      {children}
    </ShikiProvider>
  );
}

/** 功能完整示例 */
export function CodeHighlightedFullFeaturedDemo() {
  return (
    <DemoProvider>
      <CodeHighlighted
        code={`import { ShikiProvider, CodeHighlighted } from "@lark-ui/core/code";

export function CodeExample({ code, language }: Props) {
  return (
    <ShikiProvider
      engine="javascript"
      languages={["tsx", "typescript", "bash", "json"]}
    >
      <CodeHighlighted
        code={code}
        lang={language}
        showCopyButton
      />
    </ShikiProvider>
  );
}`}
        lang="tsx"
        showCopyButton
        highlightLines={[6, 7, 8, 9]}
      />
    </DemoProvider>
  );
}

共享 Provider

多个代码块可以共享同一个 ShikiProvider。 Shiki 只加载一次,供所有代码块复用。

const config = { theme: "dark" };
npm run build
{ "success": true }
import { ShikiProvider, CodeHighlighted } from "@lark-ui/core/code";
import { ReactNode } from "react";

/**
 * Wrapper component that provides Shiki context for all demos.
 * This loads Shiki once and shares it across all CodeHighlighted instances.
 */
function DemoProvider({ children }: { children: ReactNode }) {
  return (
    <ShikiProvider
      engine="javascript"
      languages={[
        "tsx",
        "typescript",
        "javascript",
        "bash",
        "json",
        "css",
        "html",
      ]}
    >
      {children}
    </ShikiProvider>
  );
}

/** 多个代码块共享同一个 provider */
export function CodeHighlightedSharedProviderDemo() {
  return (
    <DemoProvider>
      <div className="space-y-4">
        <CodeHighlighted
          code={`const config = { theme: "dark" };`}
          lang="typescript"
        />
        <CodeHighlighted code={`npm run build`} lang="bash" />
        <CodeHighlighted code={`{ "success": true }`} lang="json" />
      </div>
    </DemoProvider>
  );
}

主题

CodeHighlighted 使用内置固定主题,以确保所有 Lark 应用中的样式一致:

  • 浅色模式: github-light

  • 深色模式: vesper

暂不支持自定义主题。这样可以确保应用中所有代码块的视觉一致性。

服务端用法

对于 SSR 框架(Next.js RSC、Astro、Remix),请使用服务端工具在构建时完成高亮。

单次高亮

// Next.js RSC or Astro
import { highlightCode } from "@lark-ui/core/code/server";

export default async function Page() {
  const html = await highlightCode(`const x = 1;`, "typescript");

  return <pre dangerouslySetInnerHTML={{ __html: html }} />;
}

可复用的高亮器

// For multiple highlights, reuse the highlighter
import { createServerHighlighter } from "@lark-ui/core/code/server";

const highlighter = await createServerHighlighter({
  languages: ["tsx", "bash", "json"],
});

const html1 = highlighter.highlight(code1, "tsx");
const html2 = highlighter.highlight(code2, "bash");

highlighter.dispose(); // Clean up when done

自定义 Hook

使用 useShikiHighlighter 实现自定义方案。

import { useShikiHighlighter } from "@lark-ui/core/code";

function CustomCodeBlock({ code, lang }) {
  const { highlight, isLoading, isReady, error } = useShikiHighlighter();

  if (error) {
    return <div className="text-red-500">Failed to load highlighter</div>;
  }

  if (isLoading) {
    return (
      <pre className="animate-pulse">
        <code>{code}</code>
      </pre>
    );
  }

  const html = highlight(code, lang);

  // null means highlighting failed — render plain text
  if (html === null) {
    return (
      <pre>
        <code>{code}</code>
      </pre>
    );
  }

  return <pre dangerouslySetInnerHTML={{ __html: html }} />;
}

国际化

在 provider 层级为所有代码块统一设置按钮文案,也可以按组件单独覆盖。

// Set labels at the provider level for all code blocks
<ShikiProvider
  engine="javascript"
  languages={["tsx", "bash"]}
  labels={{ copy: "Copier", copied: "Copié!" }}
>
  <App />
</ShikiProvider>

// Or override at the component level
<CodeHighlighted
  code={code}
  lang="tsx"
  showCopyButton
  labels={{ copy: "Copy code", copied: "Done!" }}
/>

框架集成

Next.js App Router

// app/providers.tsx
"use client";

import { ShikiProvider } from "@lark-ui/core/code";

export function Providers({ children }) {
  return (
    <ShikiProvider engine="javascript" languages={["tsx", "bash", "json"]}>
      {children}
    </ShikiProvider>
  );
}

// app/layout.tsx
import { Providers } from "./providers";

export default function RootLayout({ children }) {
  return (
    <html>
      <body>
        <Providers>{children}</Providers>
      </body>
    </html>
  );
}

Astro(静态)

对于静态站点,使用服务端高亮即可实现零客户端 JavaScript。

---
// src/components/CodeBlock.astro
import { highlightCode } from "@lark-ui/core/code/server";

const { code, lang } = Astro.props;
const html = await highlightCode(code, lang);
---

<div class="code-block" set:html={html} />

包体积

Shiki 会在首次渲染时懒加载。具体体积取决于你的配置:

场景语言引擎懒加载体积
最小tsx, jsonJS~75 KB
标准tsx, ts, bash, json, css, yamlJS~95 KB
完整15+ 种语言WASM~250 KB

未从 @lark-ui/core/code 导入的团队无需承担任何体积成本(0 KB)。

从 Code/CodeBlock 迁移

旧的 Code 和 CodeBlock 组件已废弃,将在 v2.0 中移除。

// Before (deprecated)
import { Code, CodeBlock } from "@lark-ui/core";
<CodeBlock code="const x = 1;" lang="ts" />

// After
import { ShikiProvider, CodeHighlighted } from "@lark-ui/core/code";

// Once at app root
<ShikiProvider engine="javascript" languages={["tsx"]}>
  <App />
</ShikiProvider>

// In components
<CodeHighlighted code="const x = 1;" lang="tsx" />

API 参考

ShikiProvider 属性

属性类型必填描述
engine”javascript” | “wasm”是

JS 体积更小(约 50KB),WASM 更准确(约 180KB)

languagesstring[]是需要支持的语言(例如 [“tsx”, “bash”])
labels{ copy?: string, copied?: string }否复制按钮的本地化文案
childrenReactNode是应用内容

CodeHighlighted 属性

属性类型必填描述
codestring是要展示的源代码
langstring是

语言标识(必须在 provider 的 languages 中)

variant”default” | “plain”否代码块的视觉样式
showLineNumbersboolean否显示行号
highlightLinesnumber[]否需要突出显示的行(从 1 开始计数)
showCopyButtonboolean否显示复制到剪贴板按钮
labels{ copy?: string, copied?: string }否为当前实例覆盖 provider 的文案
classNamestring否附加的 CSS 类名

useShikiHighlighter 返回值

属性类型描述
highlight(code, lang, options?) => string | null返回高亮后的 HTML,若尚未就绪则返回 null
isLoadingbooleanShiki 加载期间为 true
isReadyboolean可以安全调用 highlight() 时为 true
errorError | nullShiki 初始化失败时的错误