---
title: "代码块"
description: "供人阅读、比较和复制的多行代码，使用代码字体，在自身内部滚动或换行，可带页眉、行号、带标记的行、提示符和复制按钮。给出代码和它的语言，它就会自己为代码做语法高亮。"
url: "https://tanrei.chnotchy.com/zh-cn/components/code-block/"
last_updated: 2026-10-23T21:17:12.000Z
---

# 代码块

> 供人阅读、比较和复制的多行代码，使用代码字体，在自身内部滚动或换行，可带页眉、行号、带标记的行、提示符和复制按钮。给出代码和它的语言，它就会自己为代码做语法高亮。

## 概览

代码块显示供人阅读、比较和复制的代码。句子里的一个名称或一条命令用[行内代码](https://tanrei.chnotchy.com/zh-cn/components/inline-code/)。

**代码块自己做语法高亮。** 把代码和它的 `language` 交给代码块，它就根据令牌给代码上色：不用安装语法高亮器，也不用编写主题或样式表。所以代码和页面上的其他一切一样，跟随配色方案、对比度级别和设计系统。高亮只涉及颜色和字重，别无其他：字符、行、选中的内容、复制的内容，以及屏幕阅读器朗读的内容，有没有高亮都一样。

### 用法

在 Web 上，代码留在你的文档里，是一个普通的 `<pre><code>`。没有脚本它也在那里：脚本加载失败的读者、搜索引擎和页面内查找都读得到。元素负责绘制它周围的框。加载 `@tanrei/web/code.css`，可以在元素定义之前就给代码块加上填充、圆角、内边距和字体。

SwiftUI、Compose、Flutter 和 React Native 尚在计划中：本页开头各平台旁边的名称是规格为它们定下的，这些平台目前还没有提供任何实现。

**Web**

```html
<link rel="stylesheet" href="@tanrei/web/tokens.css" />
<link rel="stylesheet" href="@tanrei/web/code.css" />

<tanrei-code-block
  headline="sizes.js"
  language="js"
  language-label="JavaScript"
  copy
  copy-label="复制"
  copied-label="已复制"
  copy-failed-label="无法复制"
>
  <pre><code>const sizes = ['small', 'medium', 'large'];</code></pre>
</tanrei-code-block>

<!-- 行号、带标记的行、提示符。 -->
<tanrei-code-block label="示例" line-numbers start-line="96" highlighted-lines="98, 100-101" highlighted-label="高亮">
  <pre><code>…</code></pre>
</tanrei-code-block>

<tanrei-code-block label="安装" prompt="$" copy copy-label="复制" copied-label="已复制" copy-failed-label="无法复制">
  <pre><code>npm install @tanrei/web</code></pre>
</tanrei-code-block>

<script type="module">
  import '@tanrei/web';
</script>
```

**React**

```tsx
import { CodeBlock } from '@tanrei/react';
import '@tanrei/web/code.css';

{/* 元素会把代码排成一行一行，所以让它拥有代码：把文本传给它。 */}
<CodeBlock headline="sizes.js" language="js" languageLabel="JavaScript" code={source} copy copyLabel="复制" copiedLabel="已复制" copyFailedLabel="无法复制" />
```

`language` 是一个标识符（`tsx`、`css`、`sh`）：代码块依据它来高亮，它本身不会被画出来。页眉里的文字是 `language-label`。由脚本构建的代码块不放 `<pre><code>`，而是设置 `code` 属性，元素会自己写出 `<pre><code>`。

## 规格

**两种外观。** `filled` 是柔和的填充，用于页面上的代码。`outlined` 没有填充，只有一道细线围着，用于已有填充的卡片或面板里的代码。

**主体。** 默认情况下，行绝不会被折断。放不下的行在代码块内部滚动，页面绝不横向滚动。`wrap` 则改为折行，续行从代码下方开始，而不是从行号下方开始。`max-lines` 按行数限制高度，其余部分在代码块内部滚动。

**复制按钮**始终绘制，绝不只在悬停时出现。它绝不会盖住无法从它下面移开的代码：滚动的主体会在末尾多出这么多空间，折行的各行则在它所在的那一列之前停下。它把代码复制为纯文本，不含行号、提示符、符号和已删除的行。手动选中后复制的，正是选中的那些字符。

**带标记的行**绝不只靠颜色来标记。

| 行 | 左边缘的竖条 | 色带 | 符号 | 在该行之前朗读 |
| --- | --- | --- | --- | --- |
| 高亮 | 有 | 有 |  | `highlighted-label` |
| 新增 | 有 | 淡绿 | + | `added-label` |
| 删除 | 有 | 淡红 | − | `removed-label` |

行的列表由逗号分隔的数字和范围组成（`"3, 7-9"`）。它们按读者看到的行号计数，从 `start-line` 算起。

**从右到左。** 代码始终从左到右：在任何布局中，行、行号和滚动的起点都在左侧。只有外框会镜像，所以标题移到右侧，复制按钮移到左侧。

- Category: Containment
- Level: base
- Listing: default
- Page: https://tanrei.chnotchy.com/components/code-block/
- Spec: https://github.com/chnotchy/tanrei/blob/main/specs/code-block.spec.json

### Availability

| Design system | Has it | Notes |
| --- | --- | --- |
| Tanrei (`tanrei`) | Yes | — |
| Cupertino (Apple HIG-inspired) (`cupertino`) | Yes | — |
| M3 Expressive-like (Material 3 Expressive-inspired) (`m3-expressive-like`) | Yes | — |
| M3-like (Material 3-inspired) (`m3-like`) | Yes | — |

### Platforms

- Web: the element `<tanrei-code-block>`, registered by importing `@tanrei/web` (or only its own module, `@tanrei/web/components/code-block`).
- React: `CodeBlock` from `@tanrei/react`.

| Platform | Name | Status |
| --- | --- | --- |
| Web | `tanrei-code-block` | lagging |
| SwiftUI | `TanreiCodeBlock` | planned |
| Jetpack Compose | `TanreiCodeBlock` | planned |
| Flutter | `TanreiCodeBlock` | planned |
| React Native | `CodeBlock` | planned |

Names a platform gives in its own idiom:

| Spec | Web | SwiftUI | Jetpack Compose | Flutter | React Native |
| --- | --- | --- | --- | --- | --- |
| `title` (prop) | `headline` | `title` | `title` | `title` | `title` |
| `highlight` (prop) | `highlight` | `highlightsSyntax` | `highlightSyntax` | `highlightSyntax` | `highlight` |
| `wrap` (prop) | `wrap` | `wrapsLines` | `softWrap` | `softWrap` | `wrap` |
| `lineNumbers` (prop) | `lineNumbers` | `showsLineNumbers` | `showLineNumbers` | `showLineNumbers` | `showLineNumbers` |
| `maxLines` (prop) | `maxLines` | `lineLimit` | `maxLines` | `maxLines` | `maxLines` |
| `copy` (prop) | `copy` | `showsCopyButton` | `showCopyButton` | `showCopyButton` | `copy` |
| `copied` (event) | `copied` | `onCopied` | `onCopied` | `onCopied` | `onCopied` |
| `copyFailed` (event) | `copyfailed` | `onCopyFailed` | `onCopyFailed` | `onCopyFailed` | `onCopyFailed` |

Statuses: `planned` — In the inventory. Nothing shippable exists yet. `lagging` — An implementation of an earlier spec exists; it has not caught up with the current one. `alpha` — Implemented with tests. The API may still change. `beta` — Feature complete and at parity. Only fixes are expected. `stable` — Covered by semantic versioning. `deprecated` — Still shipped; scheduled for removal.

### Anatomy

- `container`: The block: a quiet fill (filled) or no fill inside one hairline (outlined), with small corners. As wide as its layout gives it.
- `outline` (optional): The outlined look's edge: one hairline inside the container.
- `header` (optional): A row above the code that holds the title, the language and, where there is one, the copy button. It has no fill and no line of its own: it is the top of the same container.
- `title` (optional): What the code is: a file name or a few words. At the start of the header.
- `language` (optional): The language label: the language the code is in, in the product's words. At the end of the header, before the copy button.
- `copy-button` (optional): A Copy button (its own component) that copies the code: in the header where there is one, at the block's top end corner otherwise.
- `body`: The part that holds the lines and scrolls inside the container when they do not fit.
- `code`: The code: its lines, each on one line of the code's text style, each run in the color and weight of its syntax role where the code is highlighted.
- `line-number` (optional): A line's number, in the gutter at the left of the code. Drawn, not text.
- `mark` (optional): A bar at the left edge of a highlighted, an added or a removed line.
- `sign` (optional): A plus or a minus in the gutter of an added or a removed line. Drawn, not text.
- `prompt` (optional): A prompt drawn before each line of a block of commands. Drawn, not text.

### Props

| Prop | Type | Default | Web attribute | Description |
| --- | --- | --- | --- | --- |
| `code` | `string` | `""` | `code` | The code as plain text, lines separated by line breaks. It is what is drawn, what is highlighted and what is copied. Ignored where runs are given: their texts, joined, are the code. |
| `variant` | `enum`: `filled`, `outlined` | `"filled"` | `variant` | filled: a quiet fill, for code on a page. outlined: no fill inside one hairline, for code inside a container that is already filled (a card, a panel). A design system may add values. |
| `size` | `enum`: `small`, `medium` | `"medium"` | `size` | medium sets the code in the code role (13), for a page and a panel. small sets it in the small code role (12) with less padding, for dense interfaces. A design system may add values. |
| `title` | `string` | `""` | — | A file name or a few words that say what the code is ("button.tsx", "Response"). Drawn in the header and used as the block's accessible name. |
| `language` | `string` | `""` | `language` | The language the code is written in, as an identifier ("tsx", "css", "swift", "sh"), read without regard to case. It is what the block highlights by (COD-19, COD-27); it is not drawn. Empty, "text" and "plain" mean code that has no syntax; a language the highlighter does not know is drawn plain. |
| `languageLabel` | `string` | `""` | `language-label` | The language in the product's words ("TypeScript", "Shell"), drawn in the header. A label only: the block does not highlight by it, and draws no label of its own for language. |
| `highlight` | `boolean` | `true` | `highlight` | True: the block highlights the code by itself where it can (COD-19). False: it never does, whatever language says; runs the product gives are still drawn in their colors. |
| `label` | `string` | `""` | `label` | The block's accessible name where it has no title ("Example", "Request body"), in the product's language. Not drawn. A block that can scroll needs a title or a label. |
| `wrap` | `boolean` | `false` | `wrap` | False: a line is never broken, and lines that do not fit scroll sideways inside the block. True: a line that does not fit continues on the next row, and nothing scrolls sideways. |
| `lineNumbers` | `boolean` | `false` | `line-numbers` | Draws each line's number in a gutter at the left of the code. |
| `startLine` | `number` | `1` | `start-line` | The number of the first line: an excerpt of a file keeps the file's numbers. A whole number of 1 or more. |
| `highlightedLines` | `string` | `""` | `highlighted-lines` | The lines the text around the block talks about, by number, as numbers and ranges separated by commas ("3, 7-9"). Numbers are the ones lineNumbers would draw (they count from startLine). |
| `addedLines` | `string` | `""` | `added-lines` | The lines a change adds, written as highlightedLines is. |
| `removedLines` | `string` | `""` | `removed-lines` | The lines a change takes away, written as highlightedLines is. They are drawn and are left out of what the copy button copies. |
| `highlightedLabel` | `string` | `""` | `highlighted-label` | What assistive technology reads before a highlighted line ("Highlighted"), in the product's language. Required while highlightedLines names a line. |
| `addedLabel` | `string` | `""` | `added-label` | What assistive technology reads before an added line ("Added"). Required while addedLines names a line. |
| `removedLabel` | `string` | `""` | `removed-label` | What assistive technology reads before a removed line ("Removed"). Required while removedLines names a line. |
| `prompt` | `string` | `""` | `prompt` | A prompt ("$", ">") drawn before every line that is not empty, for a block of commands to type. It is not part of the code: it is not selected, not copied and not read. |
| `maxLines` | `number` | — | `max-lines` | The most lines shown at once; more than that scroll up and down inside the block. Null shows every line. |
| `copy` | `boolean` | `false` | `copy` | Draws a copy button that copies the code. |
| `copyLabel` | `string` | `""` | `copy-label` | The copy button's accessible name ("Copy"), in the product's language. Required while copy is true. |
| `copiedLabel` | `string` | `""` | `copied-label` | What the copy button announces when the code has been copied ("Copied"). Required while copy is true. |
| `copyFailedLabel` | `string` | `""` | `copy-failed-label` | What the copy button announces when the platform refuses the copy ("Could not copy"). Required while copy is true. |

### Events

| Event | Description |
| --- | --- |
| `copied` | The code was copied by the block's copy button; carries the text that was copied. |
| `copyFailed` | The platform refused the copy asked for by the block's copy button. |

### Item: `run`

A piece of the code that is one kind of thing — a comment, a keyword, a string, a function's name — as the block's highlighter found it, or as the product names it where the product gives the runs. The runs' texts, in order, are the code.

Names: Web `span`, SwiftUI `TanreiCodeRun`, Jetpack Compose `TanreiCodeRun`, Flutter `TanreiCodeRun`, React Native `CodeRun`.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `text` | `string` | `""` | The run's characters, exactly as in the code. It may hold line breaks: a run may span lines. |
| `syntax` | `enum`: `plain`, `comment`, `keyword`, `string`, `constant`, `function`, `type`, `tag`, `property`, `punctuation` | `"plain"` | What the run is. comment: a comment or a documentation comment. keyword: one of the language's own words (a keyword, a storage or modifier word, an at-rule, an annotation, an operator written as a word). string: text written in the code (a string, a character, a regular expression, the value of a markup attribute). constant: a value that is not text (a number, a boolean or null, a named constant, a unit, a color value, an escape inside a string). function: the name of a function or a method, declared or called. type: the name of a type (a class, a structure, an interface, an enumeration, a built-in type, a namespace). tag: what markup and style sheets address (an element's name, a component's name in markup, a selector). property: a name that belongs to something (a property, a key, a markup attribute, a style declaration's property, a command's option). punctuation: brackets, separators and the delimiters of markup. plain: none of these — variables, parameters, operators written as signs, text between tags. The values are those of the token axis comp.code-block.syntax and plain; a design system may add values to that axis. |

### States

`enabled`, `focused`

### Accessibility

- Role: `group`
- Labeling: The block is a group named by title, or by label where it has no title; inside it the code is text with the role of code where the platform has one. The copy button is named by copyLabel. Line numbers, prompts, signs and bars are hidden; a marked line is preceded by its label in words (highlightedLabel, addedLabel, removedLabel).
- Minimum target size: yes

| Keys | Action |
| --- | --- |
| Tab | Moves focus to the copy button where there is one, then to the body while it can scroll. A block that neither scrolls nor copies is not a stop. |
| Arrow keys, Page Up, Page Down, Home, End | Scroll the focused body, as the platform scrolls any region. |
| Enter or Space | On the copy button: copies the code (CPY-2). |

- The only target is the copy button, whose hit area meets the minimum target by its own spec (CPY-1, BTN-5) though it is drawn 32 high. The body is scrolled, not pressed.
- A body that scrolls must be reachable by keyboard (WCAG 2.1.1) and so is a focus stop with a visible focus indicator (COD-7); one that does not scroll is not, so a page of short examples adds no stops. A group, not a landmark: a page may hold hundreds of blocks.
- Reflow (WCAG 1.4.10): code is two-dimensional content, so sideways scrolling inside the block is allowed, and the page itself never scrolls sideways (COD-4, COD-24). wrap is for a product that prefers no sideways scrolling at all.
- A marked line is never marked by color alone (WCAG 1.4.1): a highlighted line has a bar and a band and its label; an added or a removed line has a bar, a plus or a minus and its label (COD-15, COD-16). Syntax colors carry no meaning a reader needs: the same code drawn plain says the same thing, a role is never exposed (COD-22), and keywords are also told by weight. With a red-green color vision deficiency some of the default system's six hues draw together — the green of a string and the red of a tag's name first — beside the neutral tones and the keyword's weight; nothing is lost but a distinction between kinds of words.
- Contrast: the code, the line numbers, the prompt and the signs are roles the token invariants hold at 4.5:1 on every surface (7:1 in the high-contrast schemes). Every syntax color is held by the build at the same ratios against the block's fill, against the band of a highlighted line and against every surface role, which is what an outlined block may stand on, in each system. The bars are primary, success and error, held at the same ratios, above the 3:1 a mark needs. The outlined look's edge is decorative.
- An outlined block is read on whatever it is placed on. On a surface that is correct. On a colored container (a callout) the syntax colors are not paired with that container: use filled there, which brings its own surface.
- The copy button is always drawn (COD-9): one that appears only under a pointer cannot be found by touch, and one that appears on focus moves under a keyboard user. Its confirmation is announced by the Copy button's own live region (CPY-5).
- Highlighting adds nothing for assistive technology and takes nothing away: the code is the same text before and after the colors arrive, no live region speaks of them, and the body's scroll position, the selection and the focus are kept (COD-28). Colors arrive in one frame, without a motion, so nothing flashes more than once.
- Screen readers read code as text, symbol by symbol as the person's settings say. The code block adds no line numbers or roles to that reading; the marks' labels are the only words it adds.
- Code is not translated and not spell-checked (COD-2); comments in it are the author's language and are read with the page's voice unless the product marks their language.

### Behaviour

Requirements in EARS form, each with its stable id.

- **COD-1** THE code block SHALL draw a container filled with the container color of its variant (comp.code-block.filled.container.color for filled, comp.code-block.outlined.container.color for outlined), with corners comp.code-block.container.shape eased by sys.shape.corner-smoothing and no elevation, as wide as its layout gives it and never wider, and SHALL bring no space outside itself: the layout it sits in spaces it (PRS-15). WHILE variant is outlined it SHALL draw an edge comp.code-block.outline.width wide in comp.code-block.outline.color inside the container's size, following its corners; WHILE variant is filled it SHALL draw no edge.
- **COD-2** THE code block SHALL set the code in the text style of its size, taken whole (comp.code-block.code.typescale.medium for medium, and so on), in comp.code-block.code.color where a run names no syntax role, every line of the code on one line of that style; it SHALL draw the characters as given — every space kept, a tab advancing to the next multiple of comp.code-block.code.tab-size columns, nothing hyphenated, transformed, translated or spell-checked — and SHALL draw no empty last line for one line break at the end of the code.
- **COD-3** THE code block SHALL pad the code by the block padding of its size above the first line and below the last (comp.code-block.container.padding-block.medium for medium, and so on) and by the inline padding of its size (comp.code-block.container.padding-inline.medium for medium, and so on) before the start of the lines, or of the gutter where there is one (COD-13), and after the end of the longest line.
- **COD-4** WHILE wrap is false THE code block SHALL NOT break a line; WHEN a line is wider than the body THE body SHALL scroll sideways inside the container, by pointer, touch, the wheel and the keyboard (COD-7), the page SHALL NOT scroll sideways for it, and the padding after the longest line SHALL scroll with the code, so that its last character can be brought clear of the container's edge. The header and the copy button SHALL NOT scroll with the code. A gesture or a wheel movement up or down over a body that cannot scroll that way SHALL scroll the page.
- **COD-5** WHILE wrap is true THE code block SHALL continue a line that does not fit on following rows: it breaks first at the spaces of the line and, where a part with no space is wider than the row, between any two characters; a following row SHALL begin at the column where the line's code begins (after the gutter and the prompt), draw no mark of its own and add no character; the body SHALL NOT scroll sideways; and what is selected or copied SHALL hold the line breaks of the code alone.
- **COD-6** WHILE maxLines is a number and the code has more lines than that THE body SHALL be maxLines lines of the code's text style high plus its paddings and SHALL scroll up and down inside the container; the header and the copy button SHALL NOT scroll with it. WHILE maxLines is null, or the code has no more lines than it, THE code block SHALL be as tall as its lines.
- **COD-7** WHILE the body can scroll, sideways or up and down, THE body SHALL be one stop in the focus order after the copy button, SHALL scroll by the arrow keys, Page Up, Page Down, Home and End as its platform scrolls any region, and, WHEN it has keyboard focus, SHALL show the focus indicator inside the container's edge, its corners following comp.code-block.container.shape, as sys.behavior.focus-style names (ring or glow), without animation; focus gained by pointer or touch SHALL NOT show it; a platform that cannot draw a choice SHALL fall back to the first value and state that in its README. WHILE the body cannot scroll it SHALL NOT be a stop in the focus order.
- **COD-8** WHILE title or languageLabel is not empty THE code block SHALL draw a header above the code, in the same container, with no fill and no line of its own: the title at the start, in comp.code-block.title.typescale and comp.code-block.title.color, on one line, laid out as text of its own direction and cut with an ellipsis at the end of that direction when it does not fit; the language label (languageLabel) at the end, before the copy button where there is one, in comp.code-block.language.typescale and comp.code-block.language.color, never cut; its items comp.code-block.header.gap apart. The header's row SHALL begin comp.code-block.copy-button.inset from the container's top edge, be as tall as the copy button where there is one and as one line of the title's text style otherwise, with its items centred on it; the title SHALL begin at the inline padding of COD-3; and the code SHALL begin comp.code-block.header.padding-block-end below the row in place of the block padding of COD-3.
- **COD-9** WHILE copy is true THE code block SHALL place a Copy button (CPY) — icon-only, of the text variant and the small size, named by copyLabel, with copiedLabel and copyFailedLabel as its two announcements — comp.code-block.copy-button.inset from the container's top edge and from its end edge: at the end of the header where there is one, and over the top end corner of the body otherwise. THE copy button SHALL be drawn whenever the block is, never only under a pointer or on focus; SHALL come before the body in the focus order and in reading order; and SHALL keep its place and size in every form it takes (CPY-7). THE container SHALL be at least as tall as the copy button plus twice that inset.
- **COD-10** WHILE copy is true and there is no header THE code block SHALL keep code readable beside the button: WHILE wrap is false the padding after the longest line (COD-3, COD-4) SHALL be widened by the button's width and that inset, so that any line's end can be scrolled clear of the button; WHILE wrap is true every row SHALL end before the button's column. THE copy button SHALL stand on a patch of the container's own color where code can pass under it.
- **COD-11** THE copy button of COD-9 SHALL copy the code as plain text: its lines in order, joined by line breaks, without line numbers, prompts, signs or labels, without the lines removedLines names, and with no line break that wrapping added. WHEN the Copy button emits copied or copyFailed THE code block SHALL emit its own event of that name, copied carrying the text.
- **COD-12** WHEN a person selects in the body THE code block SHALL select characters of the code alone: line numbers, prompts, signs, bars and the labels of COD-15 and COD-16 SHALL NOT be selectable and SHALL NOT be part of what a copied selection holds; a copied selection SHALL hold the selected characters, removed lines included where they were selected, with the code's own line breaks.
- **COD-13** WHILE lineNumbers is true THE code block SHALL draw before each line its number, counting from startLine, in the code's text style with digits of one width, in comp.code-block.line-number.color, right-aligned in a column as wide as the widest number drawn; a line that wraps SHALL carry its number on its first row only. The gutter — from the left: the bar's column (COD-15), the numbers, the signs (COD-16) — SHALL stand comp.code-block.line-number.gap from the start of the code, SHALL stay in view on the container's color while the code scrolls sideways under it, and SHALL be kept from assistive technology.
- **COD-14** THE code block SHALL read highlightedLines, addedLines and removedLines as numbers and ranges separated by commas, each number being a line's number as COD-13 counts it whether or not numbers are drawn; it SHALL ignore a number outside the code and an entry it cannot read, and in debug builds report it. A line named as both added and removed SHALL be drawn removed, and in debug builds reported; a line named as highlighted and as added or removed SHALL be drawn as both.
- **COD-15** WHILE a line is highlighted THE code block SHALL draw behind all of its rows a band of comp.code-block.line.highlighted.container.color from the container's left edge to its right, and at the container's left edge a bar comp.code-block.line.mark.width wide in comp.code-block.line.highlighted.mark.color as tall as the line; and SHALL expose highlightedLabel to assistive technology before the line's text, without drawing it. The line's code SHALL keep its colors.
- **COD-16** WHILE a line is added or removed THE code block SHALL draw at the container's left edge a bar comp.code-block.line.mark.width wide, as tall as the line, and in the gutter after the numbers a sign in the code's text style — a plus (+) for an added line, a minus (−) for a removed one — both in comp.code-block.line.added.mark.color for an added line and comp.code-block.line.removed.mark.color for a removed one; and SHALL expose addedLabel or removedLabel before the line's text, without drawing it. THE code block SHALL also draw behind the line, from the container's left edge to its right and under the bar, the sign and the code, a band in comp.code-block.line.added.container.color for an added line and comp.code-block.line.removed.container.color for a removed one, so that a reader scanning the block tells added from removed lines whatever the colors of their code. The line's code SHALL keep its syntax colors, which are held on these bands at the contrast of code text, and SHALL NOT be struck through: the sign and the label say what the line is, never the color alone.
- **COD-17** WHILE prompt is not empty THE code block SHALL draw the prompt and one space of the code's text style before the first row of every line that is not empty, in comp.code-block.prompt.color, after the gutter; following rows of a wrapped line SHALL begin under the code, not under the prompt; the prompt SHALL be kept from assistive technology and is not code (COD-11, COD-12).
- **COD-18** THE code block SHALL draw each run in the color of its syntax role — comp.code-block.syntax.color.comment for comment, comp.code-block.syntax.color.keyword for keyword, comp.code-block.syntax.color.string for string, comp.code-block.syntax.color.constant for constant, comp.code-block.syntax.color.function for function, comp.code-block.syntax.color.type for type, comp.code-block.syntax.color.tag for tag, comp.code-block.syntax.color.property for property, comp.code-block.syntax.color.punctuation for punctuation, and comp.code-block.code.color for plain — and with the weight of the code's text style plus the emphasis of its role (comp.code-block.syntax.emphasis.keyword for keyword, and so on; none for plain), whether the block's highlighter found the run (COD-19) or the product gave it (COD-29). A syntax role SHALL change a run's color and weight alone — never its size, family, spacing, slant, decoration or background — so that highlighted code and the same code drawn plain have the same lines, columns and size. A role a design system added to the axis SHALL be drawn from that role's two tokens in the same way.
- **COD-19** WHILE highlight is true, the product gives no runs (COD-29), language names a language the highlighter knows (COD-27) and the code is no longer than comp.code-block.syntax.max-length characters THE code block SHALL highlight the code by itself: its highlighter reads the code as that language and names the syntax role of every run, and the block draws the runs as COD-18 says. Highlighting SHALL change nothing but colors and weights: the code's characters, its lines, what is selected, what is copied (COD-11, COD-12) and what assistive technology reads (COD-22) are those of the code as given. In every other case THE code block SHALL draw all of the code in comp.code-block.code.color. WHEN a run names a syntax role the active design system does not have THE code block SHALL draw that run as plain, and in debug builds report the unknown role.
- **COD-20** THE code block SHALL lay out the body left to right in every layout direction (PRS-26): lines begin at the left, the gutter, the bars and the bands' start are at the left, the prompt is at the left of its line, and sideways scrolling starts at the left. WHERE the layout direction is right-to-left THE code block SHALL mirror the frame alone: the title at the right of the header, the language and the copy button at the left, and the copy button of a block without a header at the top left corner; the paddings of COD-10 SHALL then apply at the button's side. A comment written in a right-to-left script SHALL be laid out by the bidirectional algorithm inside its left-to-right line.
- **COD-21** THE code block SHALL take its layout direction from where it is used — the direction of the nearest ancestor that sets one, and the platform's own where none does — and SHALL have no direction setting of its own; WHEN that direction changes while the code block is shown THE code block SHALL draw itself for the new direction at once, without a motion of its own, keeping its scroll offsets, its selection and its focus.
- **COD-22** THE code block SHALL expose its code to assistive technology as text in reading order, line after line, with the role of code where the platform has one, inside a group named by title where it is not empty and by label otherwise; the language label SHALL be read as text of the header and language itself SHALL NOT be read; a syntax role SHALL NOT be exposed, and colors arriving or changing (COD-28, COD-30) SHALL NOT be announced; and WHEN code, the runs or a marked line changes THE code block SHALL draw and expose the new content at once, without a motion, SHALL NOT announce the change, and SHALL keep the body's scroll offsets where the content still reaches them.
- **COD-23** WHERE the platform draws with a person's own forced colors THE code block SHALL draw an edge comp.code-block.outline.width wide in the platform's text color inside its container in every variant; its code in the platform's text color whatever syntax role a run names, every run keeping the weight of its role; line numbers, prompts, signs and bars in that text color; and no band: a highlighted line is then marked by its bar, and an added or a removed line by its bar and its sign.
- **COD-24** WHILE the text size is enlarged THE code block SHALL grow its lines, its gutter and its header with the text, keeping its paddings and its corners, and the copy button SHALL keep the size and the target of its own spec; at twice the text size in a container 320 wide the body SHALL scroll inside the container (COD-4) or wrap (COD-5), the title SHALL be cut as COD-8 says, and the page SHALL NOT scroll sideways.
- **COD-25** IF code is empty and no runs are given THE code block SHALL draw nothing, take no space and expose nothing, and in debug builds report that a code block has no code. WHILE copy is true and copyLabel, copiedLabel or copyFailedLabel is empty, WHILE a line is marked and the label of its mark (highlightedLabel, addedLabel, removedLabel) is empty, and WHILE the body can scroll and both title and label are empty THE code block SHALL still draw, and in debug builds report what is missing. WHEN variant or size names a value the active design system does not have THE code block SHALL render with the default value, and in debug builds report the unknown value; a startLine below 1 or not whole SHALL be taken as 1 and a maxLines below 1 as null.
- **COD-26** THE code block SHALL NOT take a press itself and has no hovered, pressed, selected or disabled state: it draws no state layer and no ripple. What is pressed inside it is its Copy button, which answers a press as its own spec says (CPY-12 to CPY-14).
- **COD-27** THE code block SHALL read language as an identifier, without regard to case and to space around it, and match it against the names and the other names of the languages its highlighter knows. THE highlighter the code block brings SHALL know these languages: markup (html, xml, svg), css, javascript (js, mjs, cjs, jsx), typescript (ts, tsx), json (jsonc), shell (sh, bash, zsh), swift, kotlin (kt) and dart; a product SHALL be able to add a language, to replace one, and to replace the highlighter whole, once for all the code blocks it draws. WHILE language is empty, "text", "plain" or "plaintext" THE code block SHALL draw the code plain and report nothing; WHILE language names a language the highlighter does not know it SHALL draw the code plain, and in debug builds report the unknown language once for each name. THE code block SHALL NOT guess a language from the code, from title or from languageLabel.
- **COD-28** THE code block SHALL draw the code at once, plain, without waiting for its highlighter: no part of the highlighter is loaded for a block that will not use it, and a block that waits for it is complete in every other respect. WHEN the runs are ready THE code block SHALL draw every color and weight in one frame, without a motion and without a fade, moving no line and no character, changing the size of nothing, and keeping the body's scroll offsets, the selection and the focus. WHERE the runs are already with the code when the block is first drawn (code highlighted where the page was made) THE code block SHALL draw them in its first frame.
- **COD-29** WHERE the product gives runs THE code block SHALL take the runs' texts, joined in order, as the code, SHALL draw them as COD-18 says, and SHALL NOT highlight the code itself, whatever language and highlight say: code that was highlighted where the page was made, or by a highlighter the product chose for one block, is drawn as it was given. Code given with the statement that it has been highlighted and has no run with a role SHALL be drawn plain in the same way.
- **COD-30** WHEN code, language or highlight changes while the block is shown THE code block SHALL draw the new code at once and highlight it again; a result for code that is no longer the code shown SHALL be dropped, never drawn. WHERE its highlighter can answer in the same frame THE code block SHALL draw the new code with its colors in that frame. Otherwise the lines before the first line that changed SHALL keep their colors until the new runs are ready, and the lines from there on SHALL be drawn plain until then, so that code that grows at its end does not lose and regain its colors with every piece.
- **COD-31** WHILE the code is longer than comp.code-block.syntax.max-length characters THE code block SHALL draw all of it plain — never a part of it highlighted — and in debug builds report that the code is too long to highlight. Runs the product gives are drawn whatever their length.
- **COD-32** IF the highlighter cannot be loaded, fails while it reads the code, or answers with runs whose texts do not join to the code exactly THEN THE code block SHALL draw the code plain, SHALL keep everything else it draws and does — the header, the copy button, the lines, the marks, scrolling — and in debug builds report what failed. A failure in one block SHALL NOT change another block.
- **COD-33** WHILE addedLines or removedLines names a line THE code block SHALL highlight the code as the two texts it holds: the lines that are not removed, in order, are read as one text — the code as it is after the change, which is what is copied (COD-11) — and color the lines that are not removed; the lines that are not added, in order, are read as another — the code as it was before — and color the removed lines. A highlighted line and an added or a removed line SHALL keep the colors of their runs over the band and beside the bar and the sign (COD-15, COD-16).
- **COD-34** WHERE the platform has ARIA attributes (the web), WHEN the product sets an aria- attribute on the host, by the attribute or by the ARIA property that reflects it, THE code block SHALL move it to the data-aria- attribute of the same name, so that the host is no second node with its name, description or state, and SHALL expose it on its body, which SHALL be a group WHILE it has a name: its title or label, or one given so — an id reference by the elements it names in the host's tree or a tree around it, a description after its own. WHILE the title or label is not empty it is the body's name, over a name given so; a name given so SHALL count as the body's name for the report of COD-25. WHEN the product removes the aria- attribute or its data-aria- twin, or sets the ARIA property that reflects it (ariaLabel, ariaDescribedByElements…) to null, THE code block SHALL take it off that element.

### Tokens

As written in the token documents (DTCG): an alias in braces names the token it takes its value from, which each design system resolves. On the web each token is a CSS custom property: `--tanrei` and the name after `tanrei`, joined by hyphens (`tanrei.comp.code-block.…` → `--tanrei-comp-code-block-…`).

#### `tanrei.comp.code-block`

| Token | Type | Value |
| --- | --- | --- |
| `comp.code-block.filled.container.color` | `color` | `{tanrei.sys.color.surface-container}` |
| `comp.code-block.outlined.container.color` | `color` | `{"colorSpace":"srgb","components":[0,0,0],"alpha":0,"hex":"#000000"}` |
| `comp.code-block.container.shape` | `dimension` | `{tanrei.sys.shape.corner.small}` |
| `comp.code-block.container.padding-block.small` | `dimension` | `{tanrei.sys.space.space100}` |
| `comp.code-block.container.padding-block.medium` | `dimension` | `{tanrei.sys.space.space150}` |
| `comp.code-block.container.padding-inline.small` | `dimension` | `{tanrei.sys.space.space150}` |
| `comp.code-block.container.padding-inline.medium` | `dimension` | `{tanrei.sys.space.space200}` |
| `comp.code-block.outline.color` | `color` | `{tanrei.sys.color.outline-variant}` |
| `comp.code-block.outline.width` | `dimension` | `{tanrei.sys.border.hairline}` |
| `comp.code-block.code.typescale.small` | `typography` | `{tanrei.sys.typescale.code-small}` |
| `comp.code-block.code.typescale.medium` | `typography` | `{tanrei.sys.typescale.code}` |
| `comp.code-block.code.color` | `color` | `{tanrei.sys.color.on-surface}` |
| `comp.code-block.code.tab-size` | `number` | `2` |
| `comp.code-block.header.gap` | `dimension` | `{tanrei.sys.space.space100}` |
| `comp.code-block.header.padding-block-end` | `dimension` | `{tanrei.sys.space.space50}` |
| `comp.code-block.title.typescale` | `typography` | `{tanrei.sys.typescale.label-small}` |
| `comp.code-block.title.color` | `color` | `{tanrei.sys.color.on-surface}` |
| `comp.code-block.language.typescale` | `typography` | `{tanrei.sys.typescale.label-small}` |
| `comp.code-block.language.color` | `color` | `{tanrei.sys.color.on-surface-variant}` |
| `comp.code-block.copy-button.inset` | `dimension` | `{tanrei.sys.space.space75}` |
| `comp.code-block.line-number.color` | `color` | `{tanrei.sys.color.on-surface-variant}` |
| `comp.code-block.line-number.gap` | `dimension` | `{tanrei.sys.space.space200}` |
| `comp.code-block.prompt.color` | `color` | `{tanrei.sys.color.on-surface-variant}` |
| `comp.code-block.line.mark.width` | `dimension` | `{tanrei.sys.border.thick}` |
| `comp.code-block.line.highlighted.container.color` | `color` | `{tanrei.sys.color.surface-container-highest}` |
| `comp.code-block.line.highlighted.mark.color` | `color` | `{tanrei.sys.color.primary}` |
| `comp.code-block.line.added.container.color` | `color` | `{tanrei.sys.color.success-container}` |
| `comp.code-block.line.added.mark.color` | `color` | `{tanrei.sys.color.success}` |
| `comp.code-block.line.removed.container.color` | `color` | `{tanrei.sys.color.error-container}` |
| `comp.code-block.line.removed.mark.color` | `color` | `{tanrei.sys.color.error}` |
| `comp.code-block.syntax.color.comment` | `color` | `{tanrei.sys.color.on-surface-variant}` |
| `comp.code-block.syntax.color.keyword` | `color` | `{tanrei.sys.color.on-surface}` |
| `comp.code-block.syntax.color.string` | `color` | `{tanrei.sys.color.on-surface}` |
| `comp.code-block.syntax.color.constant` | `color` | `{tanrei.sys.color.on-surface}` |
| `comp.code-block.syntax.color.function` | `color` | `{tanrei.sys.color.on-surface}` |
| `comp.code-block.syntax.color.type` | `color` | `{tanrei.sys.color.on-surface}` |
| `comp.code-block.syntax.color.tag` | `color` | `{tanrei.sys.color.on-surface}` |
| `comp.code-block.syntax.color.property` | `color` | `{tanrei.sys.color.on-surface}` |
| `comp.code-block.syntax.color.punctuation` | `color` | `{tanrei.sys.color.on-surface-variant}` |
| `comp.code-block.syntax.emphasis.comment` | `number` | `0` |
| `comp.code-block.syntax.emphasis.keyword` | `number` | `{tanrei.sys.typescale.emphasis.body}` |
| `comp.code-block.syntax.emphasis.string` | `number` | `0` |
| `comp.code-block.syntax.emphasis.constant` | `number` | `0` |
| `comp.code-block.syntax.emphasis.function` | `number` | `0` |
| `comp.code-block.syntax.emphasis.type` | `number` | `0` |
| `comp.code-block.syntax.emphasis.tag` | `number` | `0` |
| `comp.code-block.syntax.emphasis.property` | `number` | `0` |
| `comp.code-block.syntax.emphasis.punctuation` | `number` | `0` |
| `comp.code-block.syntax.max-length` | `number` | `50000` |

Per-state tokens, valued by the design system's pattern rules (not written by hand):

- `comp.code-block.<variant>.<state>.<property>` for the variants `filled`, `outlined`, the states  and the properties `container.color`.

### 语法高亮

颜色有三个来源，按以下顺序取用。

1. **你提供的片段。** 在生成页面时已经高亮的代码，或者由你选定的语法高亮器高亮的代码。它们按原样绘制；无论 `language` 和 `highlight` 是什么，代码块都不会再次高亮这段代码。
2. **代码块自己的语法高亮器**：`highlight` 为 true，`language` 指的是它认识的语言，并且代码长度不超过 `comp.code-block.syntax.max-length`（50,000 个字符）时使用。
3. **普通文本**：其他所有情况。

代码会立即以普通文本绘制。颜色稍后在同一帧里一次到位，不会移动任何东西。代码发生变化时会重新读取；在末尾不断增长的代码，保留已有的颜色。

| `language` | 结果 |
| --- | --- |
| `html`、`xml`、`svg`、`css`、`javascript`（`js`、`mjs`、`cjs`、`jsx`）、`typescript`（`ts`、`tsx`）、`json`（`jsonc`）、`shell`（`sh`、`bash`、`zsh`）、`swift`、`kotlin`（`kt`）、`dart` | 高亮。不区分大小写。 |
| 空、`text`、`plain`、`plaintext` | 普通文本。不报告任何内容。 |
| 其他任何值 | 普通文本。调试构建会报告一次这个未知的语言。 |

代码块绝不猜测语言：不根据代码，不根据 `headline`，也不根据 `language-label`。简短的代码有歧义，猜错了就会给代码上错颜色。

**关闭高亮。** `highlight="false"` 为单个代码块关闭它自己的语法高亮器。你提供的片段仍然会绘制。

**长度上限。** 长度超过 `comp.code-block.syntax.max-length` 的代码整段以普通文本绘制，绝不只高亮一半。设计系统可以更改这个值。

**有新增和删除的行时**，代码块把代码读作它包含的两段文本：更改之后的代码决定未删除各行的颜色，更改之前的代码决定已删除各行的颜色。一个开启了字符串的已删除行，不会让后面的内容上错颜色。

**失败时不声张。** 语法高亮器无法加载、抛出异常，或者它的片段拼接起来与代码不完全一致时，代码保持普通文本。页眉、复制按钮、行和标记照常工作。

这些文法是有意做小的。它们用于展示代码，而不是编辑代码。在语言本身难以解析的地方，它们可能把某个片段的颜色上错，但绝不会丢掉任何一个字符。

### 在生成页面时高亮

在构建阶段生成页面的网站，可以在构建时高亮。这样颜色在首次绘制时就已经在那里，浏览器也不用加载语法高亮器。`highlightToHtml` 就是元素使用的那个函数，它可以在 Node 中运行。

```js
import { highlightToHtml } from '@tanrei/web/highlight';

const html = await highlightToHtml(source, 'tsx');
// <tanrei-code-block language="tsx"><pre><code data-syntax-of="tsx">${html}</code></pre></tanrei-code-block>
```

`<code>` 上的 `data-syntax-of` 说明这段代码已经高亮过。元素按原样绘制它，不导入任何东西。

### 使用你自己的语法高亮器

`@tanrei/web/highlight` 是一个独立的模块，没有任何依赖。元素在某个代码块第一次需要它时导入它，并在某种语言第一次被用到时导入该语言的文法。

| 导出 | 作用 |
| --- | --- |
| `highlight(code, language)` | 返回片段；语言不认识时返回 `null`。某种语言第一次使用时返回 Promise，之后返回值。 |
| `highlightToHtml(code, language, { lines })` | 返回 `<code>` 的内部 HTML。带 `lines` 时，每行一个 `<span data-line>`。 |
| `registerLanguage(names, grammar)` | 添加一种语言，或替换一种语言。文法是数据：若干具名的状态，每个状态是一组规则，每条规则有一个模式、一个角色，以及要进入或离开的状态。它也可以是一个导入文法的函数。 |
| `loadLanguage(language)` | 赶在该语言的第一段代码出现之前加载文法。 |
| `setHighlighter(fn)` | 整个替换语法高亮器。传入 `null` 会为整个页面关闭自动高亮。 |
| `languages()` | 返回各种语言可用的全部名称。 |
| `foldScope(scopes, text)` | 按下面的表格，返回带点号的作用域名称所对应的角色。 |
| `tokenize(grammar, code)`、`checkGrammar(grammar)` | 用于测试你编写的文法。 |

已经有一个信得过的语法高亮器的产品，也可以把 `TanreiCodeBlock.highlighter` 设为一个函数 `(code, language, signal) => runs`。这样代码块会去问这个函数，Tanrei 的模块则不会加载。

### 语法角色

| 角色（`data-syntax`） | 它是什么 | 在默认系统中 |
| --- | --- | --- |
| `comment` | 注释、文档注释 | 比代码更低调 |
| `keyword` | 语言自身的词：关键字、修饰符、at 规则、注解、写成单词的运算符 | 紫色，加重一档字重 |
| `string` | 写在代码里的文本：字符串、字符、正则表达式、标记语言中属性（attribute）的值 | 绿色 |
| `constant` | 不是文本的值：数字、布尔值、null、具名常量、单位、颜色值、转义序列 | 橙色 |
| `function` | 函数或方法的名称，无论是声明还是调用 | 蓝色 |
| `type` | 类型的名称：类、结构体、接口、内置类型、命名空间 | 蓝绿色 |
| `tag` | 标记语言和样式表所指向的对象：元素的名称、标记中组件的名称、选择器 | 红色 |
| `property` | 属于某样东西的名称：属性（property）、键、标记语言的属性（attribute）、样式属性、命令的选项 | 蓝色，色调更接近代码的颜色 |
| `punctuation` | 括号、分隔符、标记语言的定界符 | 比代码更低调 |
| 普通（没有 span） | 其他任何内容：变量、参数、写成符号的运算符、标签之间的文本 | 代码的颜色 |

每个角色有两个令牌：一个颜色（`comp.code-block.syntax.color.*`）和一个字重档位（`comp.code-block.syntax.emphasis.*`）。这些角色是一条令牌轴，所以设计系统可以添加新的角色。默认系统的绿色和红色来自语法专用的调色板，色相与成功色和错误色相近。新增的行和删除的行靠竖条、符号和标签来分辨，绝不只靠颜色。角色只改变颜色和字重，所以高亮的代码和普通代码有相同的行和列。

片段是 `<code>` 里的一个 `<span data-syntax="…">`。span 之外的文本是普通文本。

### 把语法高亮器的作用域归并到角色

有些语法高亮器用带点号的作用域（scope）名称来命名找到的东西，这些名称出自同一套通用词汇。`foldScope` 把它们归并到这些角色，让你的语法高亮器和 Tanrei 的语法高亮器给出相同的颜色。一个词法单元的各个作用域，从最具体的开始向外依次尝试。在同一个作用域内，第一个匹配的行生效。不匹配任何一行的作用域会被跳过，什么都没匹配到的词法单元是普通文本。

| # | 作用域的开头 | 角色 |
| --- | --- | --- |
| 1 | `comment`、`punctuation.definition.comment` | `comment` |
| 2 | `constant.character.escape`、`constant.numeric`、`constant.language`、`constant.other`、`keyword.other.unit`、`support.constant`、`variable.other.constant`、`variable.other.enummember` | `constant` |
| 3 | `string`、`punctuation.definition.string`、`markup.inline.raw`、`markup.raw` | `string` |
| 4 | `entity.name.tag`、`support.class.component`、`meta.selector`，以及样式表中的 `entity.other.attribute-name` | `tag` |
| 5 | `entity.other.attribute-name`、`support.type.property-name`、`meta.property-name`、`meta.object-literal.key`、`variable.other.property`、`variable.other.object.property`、`support.type.vendored.property-name`、`variable.parameter.option` | `property` |
| 6 | `entity.name.function`、`support.function`、`variable.function`、`meta.function-call.generic` | `function` |
| 7 | `entity.name.type`、`entity.name.class`、`entity.name.namespace`、`entity.other.inherited-class`、`support.type`、`support.class`、`storage.type.primitive`、`storage.type.built-in`、`keyword.type` | `type` |
| 8 | 文本由字母组成的 `keyword.operator`（`new`、`typeof`、`in`） | `keyword` |
| 9 | 其余的 `keyword.operator` | 普通 |
| 10 | `keyword`、`storage`、`variable.language`、`meta.decorator`、`punctuation.decorator`、`entity.name.function.decorator`、`markup.heading` | `keyword` |
| 11 | `punctuation`、`meta.brace`、`meta.delimiter` | `punctuation` |
| 12 | `variable`、`meta`、`source`、`text`、`markup`、`invalid` | 普通 |

- 字符串的引号是字符串的一部分。字符串里的转义序列是常量。
- JSON 的键是属性，它们的值是字符串和常量。
- 装饰器的名称是关键字。
- `invalid` 是普通文本。显示代码的组件不评判代码。
- 新增和删除是行的属性（`added-lines`、`removed-lines`），不是片段的属性。

### Web 上绘制方式的不同之处

- 元素把每一行包进 `<span data-line>`，给它一个框。它会移动你的节点，在换行处拆开文本和片段，但不给代码添加任何字符。如果框架拥有 `<code>` 的子节点，就应该改为传入 `code`，或者自己渲染 `[data-line]`。
- 带标记的行的标签是该行代码之前的一个隐藏 `<span>`。它是 `<code>` 的 `textContent` 的一部分，但不在复制的内容之内。
- outlined 外观画在它所处的任何背景上。如果那不是表面颜色，请在 `--tanrei-code-block-ground` 里指明，这样代码从行号和复制按钮下面滚过时，它们才有底色可依。
- 在元素定义之前，`code.css` 绘制填充、圆角、内边距和片段的颜色。页眉、复制按钮、行号和标记需要元素。
- `highlight` 默认为 true，所以它的属性（attribute）是为了关闭它才写的：`highlight="false"`。属性（property）接受布尔值。
- 元素把它自己的片段作为 span 逐行写进你的 `<code>`，并把它们标记为自己写的。如果框架拥有 `<code>` 的子节点，就应该传入 `code`，让元素来写。
- 长度上限读取自自定义属性 `--tanrei-comp-code-block-syntax-max-length`，取层叠最终给到这个代码块的值。
- 使用单文件包的页面，语法高亮器已经包含在其中。以模块形式导入 `@tanrei/web` 的页面，则按需加载它。

## 指南

### 推荐

- 给可以滚动的代码块加上 `headline` 或 `label`。滚动的主体是一个焦点停靠点，需要名称。
- 在卡片或面板里使用 `outlined`，在页面上和有颜色的容器上使用 `filled`。
- 一组需要用户输入的命令用提示符。提示符不会被复制。
- 给每个代码块指定 `language`。没有语法的文本用 `language="text"`。
- 多个文件或多种语言放进[标签页](https://tanrei.chnotchy.com/zh-cn/components/tabs/)，每个标签页里放一个代码块。

### 避免

- 不要用代码块表示句子里的一个名称。请使用行内代码。
- 不要指望靠语法颜色来说明什么。同样的代码以普通文本绘制时，必须表达同样的意思。
- 不要把命令和它们的输出混在同一个提示符下。每个非空行都会得到提示符。请用两个代码块。

## 无障碍

### 组件负责的部分

- 代码是 `code` 元素，位于一个由 `headline` 或 `label` 命名的组里。
- 可以滚动的主体是焦点顺序中的一个停靠点，排在复制按钮之后，用方向键滚动。放得下的主体不是停靠点，所以满是简短示例的页面不会增加任何停靠点。
- 行号、符号、竖条和提示符对辅助技术隐藏。带标记的行之前有用文字写出的标签。
- 在 320 宽和两倍文本大小下，页面都绝不会因为代码块而横向滚动。
- 在强制颜色模式下，每种外观都会多出一道边线，所有代码都是文本颜色，竖条和符号保留。
- 高亮不会给辅助技术增加任何东西。不暴露任何角色，颜色到位时也不朗读。选区、焦点和滚动位置都保持不变。
- 对于红绿色觉异常的人，六种色相中有几种看起来会彼此接近，首先是字符串的绿色和标签（tag）名称的红色。关键字还可以靠字重来分辨。

### 需要你做的事

- 使用 `copy` 时，请提供 `copy-label`、`copied-label` 和 `copy-failed-label`，以及你用到的每种标记的标签，都用你的产品的语言来写。
- 在代码块周围的文字里说明高亮的行展示了什么。标签只说明它被高亮了。
