Chuyển tới nội dung

Pro đang mở bán trước. Cài đặt mở từ tháng 1/2027. Xem Pro

Component

CodeBlock

Một khối mã để đọc và sao chép: phần đầu tùy chọn với tên tệp và ngôn ngữ, nút sao chép báo khi đã chép, số dòng, dòng được đánh dấu, và dòng dài cuộn ngang hoặc xuống dòng. Bộ tô màu nhỏ có sẵn tô TS, JS, JSON, CSS, HTML và shell bằng token màu chữ; truyền highlight để cắm bộ khác.

  • npm: 2 trực tiếp, 4 tổng
  • registry: 3 trực tiếp, 3 tổng

Xem trước

app/page.tsxtsx
import { Button } from "@/components/ui/button"export default function Page() {  // Save the draft before leaving.  return <Button variant="solid" onClick={() => save(42)}>Save</Button>}

Props

  • language
  • filename
  • showLanguage
  • variant
  • size
  • showLineNumbers
  • defaultWrap
  • showWrapButton
  • showCopyButton
  • sample
import { CodeBlock } from "@/components/ui/code-block"

const codeSampleTsx = "import { Button } from \"@/components/ui/button\"\n\nexport default function Page() {\n  // Save the draft before leaving.\n  return <Button variant=\"solid\" onClick={() => save(42)}>Save</Button>\n}"
<CodeBlock language="tsx" filename="app/page.tsx" showLineNumbers code={codeSampleTsx} />

Cách dùng

Khi nào dùng

  • Hiện mã để đọc hoặc chép trong tài liệu, hướng dẫn cài đặt hoặc changelog.
  • Chỉ ra những dòng quan trọng của một tệp, với số dòng và dòng được đánh dấu.

Khi nào không dùng

  • Một từ hoặc tên ngắn trong câu. Dùng thẻ code trong văn bản.
  • Mã người đọc sửa. Dùng trình soạn mã hoặc Textarea.
  • Một log dài đang chạy. Dùng khung log cuộn.

Biến thể

variant

default nằm lõm trong trang hoặc card, surface nổi trên vùng lõm, plain không nền không viền, cho mã trong một panel khác.

  • app/page.tsxtsx
    import { Button } from "@/components/ui/button"export default function Page() {  // Save the draft before leaving.  return <Button variant="solid" onClick={() => save(42)}>Save</Button>}

    defaultmặc định

  • app/page.tsxtsx
    import { Button } from "@/components/ui/button"export default function Page() {  // Save the draft before leaving.  return <Button variant="solid" onClick={() => save(42)}>Save</Button>}

    surface

  • app/page.tsxtsx
    import { Button } from "@/components/ui/button"export default function Page() {  // Save the draft before leaving.  return <Button variant="solid" onClick={() => save(42)}>Save</Button>}

    plain

import { CodeBlock } from "@/components/ui/code-block"

const codeSampleTsx = "import { Button } from \"@/components/ui/button\"\n\nexport default function Page() {\n  // Save the draft before leaving.\n  return <Button variant=\"solid\" onClick={() => save(42)}>Save</Button>\n}"
<CodeBlock language="tsx" filename="app/page.tsx" showLineNumbers code={codeSampleTsx} />
<CodeBlock language="tsx" filename="app/page.tsx" variant="surface" showLineNumbers code={codeSampleTsx} />
<CodeBlock language="tsx" filename="app/page.tsx" variant="plain" showLineNumbers code={codeSampleTsx} />

size

Cỡ chữ mã, chiều cao dòng và padding: chữ 12, 14 hoặc 16px.

  • app/page.tsxtsx
    import { Button } from "@/components/ui/button"export default function Page() {  // Save the draft before leaving.  return <Button variant="solid" onClick={() => save(42)}>Save</Button>}

    sm

  • app/page.tsxtsx
    import { Button } from "@/components/ui/button"export default function Page() {  // Save the draft before leaving.  return <Button variant="solid" onClick={() => save(42)}>Save</Button>}

    mdmặc định

  • app/page.tsxtsx
    import { Button } from "@/components/ui/button"export default function Page() {  // Save the draft before leaving.  return <Button variant="solid" onClick={() => save(42)}>Save</Button>}

    lg

import { CodeBlock } from "@/components/ui/code-block"

const codeSampleTsx = "import { Button } from \"@/components/ui/button\"\n\nexport default function Page() {\n  // Save the draft before leaving.\n  return <Button variant=\"solid\" onClick={() => save(42)}>Save</Button>\n}"
<CodeBlock language="tsx" filename="app/page.tsx" size="sm" showLineNumbers code={codeSampleTsx} />
<CodeBlock language="tsx" filename="app/page.tsx" showLineNumbers code={codeSampleTsx} />
<CodeBlock language="tsx" filename="app/page.tsx" size="lg" showLineNumbers code={codeSampleTsx} />

Ví dụ

Tệp

Tên tệp và ngôn ngữ ở phần đầu, nút sao chép ở cuối.

app/page.tsxtsx
import { Button } from "@/components/ui/button"export default function Page() {  // Save the draft before leaving.  return <Button variant="solid" onClick={() => save(42)}>Save</Button>}
import { CodeBlock } from "@/components/ui/code-block"

const codeSampleTsx = "import { Button } from \"@/components/ui/button\"\n\nexport default function Page() {\n  // Save the draft before leaving.\n  return <Button variant=\"solid\" onClick={() => save(42)}>Save</Button>\n}"
<CodeBlock filename="app/page.tsx" language="tsx" code={codeSampleTsx} />

Số dòng và dòng được đánh dấu

highlightLines đánh dấu dòng bằng nền info và một vạch info; đếm từ startLine.

app/page.tsxtsx
import { Button } from "@/components/ui/button"export default function Page() {  // Save the draft before leaving. (highlighted)  return <Button variant="solid" onClick={() => save(42)}>Save</Button> (highlighted)}
import { CodeBlock } from "@/components/ui/code-block"

const codeSampleTsx = "import { Button } from \"@/components/ui/button\"\n\nexport default function Page() {\n  // Save the draft before leaving.\n  return <Button variant=\"solid\" onClick={() => save(42)}>Save</Button>\n}"
<CodeBlock filename="app/page.tsx" language="tsx" code={codeSampleTsx} showLineNumbers highlightLines={[4, 5]} />

Đoạn trích

startLine đánh số đoạn trích theo vị trí của nó trong tệp.

tokens.csscss
:root {  --radius-container: 12px; (highlighted)  --spacing-lg: 16px;}
import { CodeBlock } from "@/components/ui/code-block"

const codeSampleCss = ":root {\n  --radius-container: 12px;\n  --spacing-lg: 16px;\n}"
<CodeBlock filename="tokens.css" language="css" code={codeSampleCss} showLineNumbers startLine={42} highlightLines={[43]} />

Xuống dòng

Dòng dài mặc định cuộn ngang. showWrapButton thêm nút bật tắt; defaultWrap bắt đầu ở chế độ xuống dòng.

bash
npx shadcn@latest add https://ui.example.com/r/code-block.json https://ui.example.com/r/button.json --overwrite --yes
import { CodeBlock } from "@/components/ui/code-block"

const codeSampleLong = "npx shadcn@latest add https://ui.example.com/r/code-block.json https://ui.example.com/r/button.json --overwrite --yes"
<CodeBlock language="bash" code={codeSampleLong} showWrapButton />

Không có phần đầu

Không có tên tệp hoặc ngôn ngữ thì nút sao chép nổi ở góc trên cuối.

npx shadcn@latest add @werewolf/code-block
import { CodeBlock } from "@/components/ui/code-block"

<CodeBlock language="bash" showLanguage={false} code="npx shadcn@latest add @werewolf/code-block" />

Văn bản thuần

highlight={false} tắt màu; ngôn ngữ không có ngữ pháp sẵn cũng hiện thuần.

notes.txt
Werewolf UITokens first, components second.Every color comes from a token.
import { CodeBlock } from "@/components/ui/code-block"

const codeSampleText = "Werewolf UI\nTokens first, components second.\nEvery color comes from a token."
<CodeBlock filename="notes.txt" highlight={false} code={codeSampleText} />

Bộ tô màu của bạn

Truyền một hàm trả về token cho từng dòng, như hàm dựng từ kết quả của một bộ tô màu phía server.

sql
SELECT name, emailFROM usersWHERE active = trueORDER BY name;
import { CodeBlock } from "@/components/ui/code-block"

const codeSampleSql = "SELECT name, email\nFROM users\nWHERE active = true\nORDER BY name;"
const SQL_KEYWORDS = /\b(SELECT|FROM|WHERE|ORDER|BY|AND|OR|true|false)\b/
const highlightSql: CodeBlockHighlighter = (code) =>
  code.split("\n").map((line) =>
    line
      .split(/(\b(?:SELECT|FROM|WHERE|ORDER|BY|AND|OR|true|false)\b)/)
      .filter(Boolean)
      .map((text) => ({ text, className: SQL_KEYWORDS.test(text) ? "text-text-purple" : undefined }))
  )
<CodeBlock language="sql" code={codeSampleSql} highlight={highlightSql} />

Mã dài

maxHeight giới hạn chiều cao; mã cuộn cả hai chiều và nhận focus cho bàn phím.

package.jsonjson
{  "name": "@werewolf/code-block",  "type": "registry:ui",  "private": false,  "version": 1,  "dependencies": ["@tabler/icons-react"],  "registryDependencies": ["@werewolf/utils", "@werewolf/button"]}
import { CodeBlock } from "@/components/ui/code-block"

const codeSampleJson = "{\n  \"name\": \"@werewolf/code-block\",\n  \"type\": \"registry:ui\",\n  \"private\": false,\n  \"version\": 1,\n  \"dependencies\": [\"@tabler/icons-react\"],\n  \"registryDependencies\": [\"@werewolf/utils\", \"@werewolf/button\"]\n}"
<CodeBlock filename="package.json" language="json" code={codeSampleJson} showLineNumbers maxHeight="160px" />

Nên và không nên

Nên

  • Ghi tên tệp khi mã thuộc về một tệp, để người đọc biết dán vào đâu.
  • Đánh dấu các dòng đã đổi hoặc được nhắc tới, và nói điều đó trong phần chữ.
  • Để dòng dài cuộn ngang cho mã cần chép; thêm nút xuống dòng để đọc trên màn hình hẹp.

Không nên

  • Đừng đặt CodeBlock giữa câu; dùng thẻ code cho một tên hoặc lệnh ngắn.
  • Đừng chỉ dựa vào màu để phân biệt dòng; dòng được đánh dấu cần chữ đi kèm.
  • Đừng thêm bộ tô màu nặng chỉ để có màu; bộ có sẵn đủ cho các ngôn ngữ thường gặp, và highlight cắm bộ khác khi thật cần.

Props

TênKiểuGiá trịMặc địnhMô tả
code bắt buộcstring--Mã, dạng văn bản thuần. Đây là thứ nút sao chép chép đi.
languagestring--Ngôn ngữ, như tsx, json, css, html hoặc bash. Hiện ở phần đầu và chọn ngữ pháp có sẵn.
filenamestring--Tên tệp ở đầu phần đầu, như app/page.tsx. Nó cũng đặt tên cho vùng code.
showLanguageboolean-trueHiện ngôn ngữ ở phần đầu.
variantenumdefault | surface | plaindefaultdefault nằm lõm trong trang hoặc card, surface nổi trên vùng lõm, plain không nền không viền, cho mã trong một panel khác.
sizeenumsm | md | lgmdCỡ chữ mã, chiều cao dòng và padding: chữ 12, 14 hoặc 16px.
showLineNumbersboolean-falseĐánh số từng dòng.
startLinenumber-1Số của dòng đầu tiên, cho một đoạn trích từ giữa tệp.
highlightLinesnumber[]--Các số dòng được đánh dấu bằng nền info, đếm từ startLine.
wrapboolean--Dòng dài xuống dòng thay vì cuộn ngang, khi được điều khiển.
defaultWrapboolean-falseTrạng thái xuống dòng ban đầu khi không được điều khiển.
onWrapChange(wrap: boolean) => void--Được gọi khi nút xuống dòng được nhấn.
showWrapButtonboolean-falseHiện nút bật tắt xuống dòng.
showCopyButtonboolean-trueHiện nút sao chép.
onCopy(code: string) => void--Được gọi với mã sau khi chép xong.
highlightboolean | CodeBlockHighlighter-truetrue dùng bộ tô màu có sẵn, false tắt màu, hoặc một hàm trả về token cho từng dòng.
maxHeightstring--Chiều cao tối đa của phần mã, như 320px; phần thừa cuộn dọc.
labels{ copy?: string; copied?: string; copyFailed?: string; wrap?: string; highlighted?: string; region?: string }--Tên các nút, thông báo và chữ đọc cho dòng được đánh dấu và vùng mã. Mặc định: Copy code, Copied, Couldn't copy, Wrap lines, (highlighted), Code. Tiếng Việt: Sao chép mã, Đã sao chép, Không sao chép được, Xuống dòng, (đánh dấu), Mã.

Cấu tạo

PhầnMô tả
rootfigure: một panel lõm, surface hoặc plain chứa phần đầu và mã.
headerfigcaption: tên tệp và ngôn ngữ ở đầu, các nút ở cuối, trên một đường kẻ nhạt.
nameTên tệp, chữ monospace, cắt bằng dấu ba chấm.
labelNgôn ngữ, như tsx, bằng chữ secondary.
actionsNút xuống dòng và nút sao chép, Button icon ghost cỡ sm. Không có phần đầu thì chúng nổi ở góc trên cuối.
contentThẻ pre cuộn ngang khi dòng dài. Nó nhận focus để bàn phím cuộn được.
lineMột dòng mã. Dòng được đánh dấu có nền info suốt chiều rộng cuộn.
lineNumberSố dòng, chữ secondary, căn phải. Chuyển sang chữ info trên dòng được đánh dấu.

Khả năng truy cập

Role: figure

PhímHành động
TabChuyển tới nút xuống dòng và nút sao chép, rồi tới phần mã, cuộn được bằng phím mũi tên khi dòng dài tràn ra.
Enter / SpaceTrên nút sao chép, chép mã. Trên nút xuống dòng, bật hoặc tắt xuống dòng.
  • Có tên tệp hoặc ngôn ngữ thì figure được đặt tên bằng phần đầu, nên mã được đọc là EN `app/page.tsx tsx`.
  • Nút sao chép tên EN `Copy code`. Sau khi chép, tên chuyển thành EN `Copied` trong hai giây và một vùng status thông báo.
  • Nút xuống dòng là nút nhấn giữ (aria-pressed), tên EN `Wrap lines`.
  • Số dòng bị ẩn khỏi trình đọc màn hình và khỏi vùng chọn, nên khi chép chỉ có mã.
  • Dòng được đánh dấu hiện bằng nền info. Hãy nói ý nghĩa của nó trong phần chữ; màu không tới được mọi người đọc.

Cài đặt

npx werewolf-ui add code-block

Chạy npx werewolf-ui init một lần trong app trước khi thêm component. Init cài token, thêm CSS import và luật cho agent. Add cài component này cùng các dependency và giữ nguyên theme của bạn. Xem Cài đặt để biết yêu cầu và cách cài qua registry.