# CodeBlock

> Several lines of code or a log on a framed code surface, with an optional header for the file name and a copy action.

Source: https://raft-design.botiverse.build/components/code-block. Generated from the current release; where it differs from what you remember, this page is right.

Several lines of code or a log, on a framed code surface that scrolls sideways instead of wrapping. An optional header names the file and holds actions such as Copy. You render the code inside, plain or highlighted.

```tsx
import {
  CodeBlock,
  CodeBlockActions,
  CodeBlockBody,
  CodeBlockHeader,
  CodeBlockTitle,
} from "@botiverse/raft-ui";
import { CodeCopyAction } from "#/lib/code-block/code-copy-action.tsx";
import { ShikiHighlightedCode } from "#/lib/code-block/shiki-highlighted-code.tsx";

const CODE = `type Message = {
  author: string;
  body: string;
};

const message: Message = {
  author: "Ada",
  body: "Shipped",
};`;

export function ShikiCodeBlockComposition() {
  return (
    <CodeBlock>
      <CodeBlockHeader>
        <CodeBlockTitle>message.ts</CodeBlockTitle>
        <CodeBlockActions>
          <CodeCopyAction code={CODE} />
        </CodeBlockActions>
      </CodeBlockHeader>
      <CodeBlockBody>
        <ShikiHighlightedCode code={CODE} language="ts" />
      </CodeBlockBody>
    </CodeBlock>
  );
}
```

## When to use

| Situation                          | Use                                                                                                                         |
| ---------------------------------- | --------------------------------------------------------------------------------------------------------------------------- |
| Several lines of code, or a log    | CodeBlock                                                                                                                   |
| One command people copy and run    | [CopyableCode](https://raft-design.botiverse.build/components/copyable-code.md)                                                                           |
| A name from code inside a sentence | [InlineCode](https://raft-design.botiverse.build/components/inline-code.md)                                                                                 |
| A diagram or a Markdown table      | The same container ([Built from existing parts](https://raft-design.botiverse.build/components.md#diagrams-and-markdown-tables)) |

## Anatomy

- `CodeBlock`: the frame. Required.
- `CodeBlockHeader`: the optional top bar, with a hairline under it.
  - `CodeBlockTitle`: the file name, in Space Mono.
  - `CodeBlockActions`: the actions at its right end.
- `CodeBlockBody`: the code panel. Render the code in a `CodeBlockPre` with its `code` inside it. Required.
- `CodeBlockPre`: the code's `pre`, keyboard-reachable while it scrolls ([Accessibility](#accessibility)).
- `CodeBlockAction`: a 32px icon button with `radius-chip`, like every control embedded in a frame. You provide its icon and what it does.

## Variants

| Variant          | Use for                                                                                                                 |
| ---------------- | ----------------------------------------------------------------------------------------------------------------------- |
| With a header    | Code from a file: the header names it                                                                                   |
| Without a header | A snippet or a log without a file name; `CodeBlockActions` placed inside the body takes its own column at its top right |
| Highlighted      | Code in a known language, highlighted with Shiki                                                                        |
| Plain            | Logs and text without a language                                                                                        |

```tsx
import {
  CodeBlock,
  CodeBlockActions,
  CodeBlockBody,
  CodeBlockHeader,
  CodeBlockPre,
  CodeBlockTitle,
} from "@botiverse/raft-ui";
import { CodeCopyAction } from "#/lib/code-block/code-copy-action.tsx";

const CODE = `const message = {
  author: "Ada",
  body: "Shipped",
};`;

export function PlainCodeBlockComposition() {
  return (
    <CodeBlock>
      <CodeBlockHeader>
        <CodeBlockTitle>message.js</CodeBlockTitle>
        <CodeBlockActions>
          <CodeCopyAction code={CODE} />
        </CodeBlockActions>
      </CodeBlockHeader>
      <CodeBlockBody>
        <CodeBlockPre>
          <code>{CODE}</code>
        </CodeBlockPre>
      </CodeBlockBody>
    </CodeBlock>
  );
}
```

```tsx
import { CodeBlock, CodeBlockActions, CodeBlockBody } from "@botiverse/raft-ui";
import { CodeCopyAction } from "#/lib/code-block/code-copy-action.tsx";
import { ShikiHighlightedCode } from "#/lib/code-block/shiki-highlighted-code.tsx";

const CODE = `export function formatAuthor(message: Message) {
  return message.author.trim() || "Unknown";
}`;

export function WithoutHeaderCodeBlockComposition() {
  return (
    <CodeBlock>
      <CodeBlockBody>
        <CodeBlockActions>
          <CodeCopyAction code={CODE} />
        </CodeBlockActions>
        <ShikiHighlightedCode code={CODE} language="ts" />
      </CodeBlockBody>
    </CodeBlock>
  );
}
```

```tsx
import {
  CodeBlock,
  CodeBlockActions,
  CodeBlockBody,
  CodeBlockHeader,
  CodeBlockTitle,
} from "@botiverse/raft-ui";
import { AnimatedCodeCopyAction } from "#/lib/code-block/code-copy-action.tsx";
import { ShikiHighlightedCode } from "#/lib/code-block/shiki-highlighted-code.tsx";

const CODE = `export function messagePreview(message: Message) {
  return message.body.slice(0, 80).trimEnd();
}`;

export function AnimatedCopyCodeBlockComposition() {
  return (
    <CodeBlock>
      <CodeBlockHeader>
        <CodeBlockTitle>message-preview.ts</CodeBlockTitle>
        <CodeBlockActions>
          <AnimatedCodeCopyAction code={CODE} />
        </CodeBlockActions>
      </CodeBlockHeader>
      <CodeBlockBody>
        <ShikiHighlightedCode code={CODE} language="ts" />
      </CodeBlockBody>
    </CodeBlock>
  );
}
```

## Behavior

- Long lines scroll sideways inside the body. The code doesn't wrap.
- After a copy, the copy icon turns into a check, then back after a moment, as in [CopyableCode](https://raft-design.botiverse.build/components/copyable-code.md).

## Content

- Put the file name in the title, with its extension: `raft.config.ts`.
- Leave the header out when there is no file name.

## Accessibility

- Give every `CodeBlockAction` an `aria-label`, such as "Copy code": it is icon-only.
- Announce a completed copy, for example with `aria-live` on the button, so the change of icon isn't the only signal.
- Keep the code in `pre` and `code`, so it is read as code and keeps its whitespace.
- Render the code in `CodeBlockPre`. A long line scrolls inside it, and while it does it is a region the keyboard can reach (`tabindex="0"`, `role="region"`), named by its `aria-label` ("Code" by default; name it after the language, "ts code"): Safari doesn't let the keyboard reach a scroller that can't take focus, and a `pre` with no role can't carry a name. Code that fits adds no Tab stop. It shows the inset ink ring on keyboard focus.

## Rules

- Set code in Space Mono, `text-mono-code`.
- Put the block on `layer-code`, with a `line-hairline` border and `radius-container`.
- Put the actions 6px from the block's corner, 4px apart. Without a header they sit in a column of their own beside the code, as wide as the actions, so no line runs under them however many there are, and the block is at least tall enough to keep 6px under them. In a header they are centred in its 40px and 6px from its end ([Shape](https://raft-design.botiverse.build/foundations/shape.md#inside-a-frame)).

## API

### CodeBlock

Framed code surface. Compose a header and a body inside it.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `render` | `ReactElement \| ((props, state) => ReactElement)` |  | Allows you to replace the component's HTML element with a different tag, or compose it with another component. |

Also takes the attributes of its element.

### CodeBlockAction

Styled action shell. The consumer owns the icon and the behavior.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `render` | `ReactElement \| ((props, state) => ReactElement)` |  | Allows you to replace the component's HTML element with a different tag, or compose it with another component. |

Also takes the attributes of its element.

### CodeBlockActions

Trailing action region. In the header it ends the header; in the body it takes a column of its own beside the code.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `render` | `ReactElement \| ((props, state) => ReactElement)` |  | Allows you to replace the component's HTML element with a different tag, or compose it with another component. |

Also takes the attributes of its element.

### CodeBlockBody

Inner code panel. Render the code in a `CodeBlockPre` (or a complete pre and code) as children.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `render` | `ReactElement \| ((props, state) => ReactElement)` |  | Allows you to replace the component's HTML element with a different tag, or compose it with another component. |

Also takes the attributes of its element.

### CodeBlockHeader

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `render` | `ReactElement \| ((props, state) => ReactElement)` |  | Allows you to replace the component's HTML element with a different tag, or compose it with another component. |

Also takes the attributes of its element.

### CodeBlockPre

The code's `pre`. A long line scrolls inside it; while it does, it is a named region the keyboard can reach (`tabindex="0"`, `role="region"`, its `aria-label`, "Code" by default), since Safari doesn't focus a scroller on its own. Code that fits adds no Tab stop.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `render` | `ReactElement \| ((props, state) => ReactElement)` |  | Allows you to replace the component's HTML element with a different tag, or compose it with another component. |

Also takes the attributes of its element.

### CodeBlockTitle

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `render` | `ReactElement \| ((props, state) => ReactElement)` |  | Allows you to replace the component's HTML element with a different tag, or compose it with another component. |

Also takes the attributes of its element.

## Changes

- 0.2.0 (Added): Added stable `CodeBlock*` and semantic `Markdown*` compound primitives.
