<CodeBlock.Root id="code-block-preview-typescript" code={`import { useState } from \"react\";export function Counter() { const [count, setCount] = useState(0); return ( <button onClick={() => setCount(c => c + 1)}> Count: {count} </button> );}`} language="typescript" lineNumbers="visible" filename="Counter.tsx"> <CodeBlock.Header /> <CodeBlock.Content /> <CodeBlock.CollapseToggle /></CodeBlock.Root>When the assistant generates or references code, unstyled monospace text sells it short. CodeBlock renders syntax-highlighted snippets with line numbers and a copy button. You can highlight specific lines to draw attention to changes or bugs, and collapse long snippets with maxCollapsedLines to keep conversations scannable.
Role: Information. For displaying data the user reads. See Design Guidelines for how component roles work.
Run this once from your project root.
npx shadcn@latest add @tool-ui/code-blockRender CodeBlock in your UI with tool-compatible props.
import { CodeBlock } from "@/components/tool-ui/code-block";export function MyComponent() { return ( <CodeBlock id="my-code-example" code={`function hello(name: string) { return \`Hello, \${name}!\`;}`} language="typescript" lineNumbers="visible" filename="hello.ts" /> );}Register this renderer so tool results display as CodeBlock.
// Backend toolimport { tool, jsonSchema } from "ai";const showCodeBlock = tool({ description: "Show a code snippet", inputSchema: jsonSchema<{}>({ type: "object", properties: {}, additionalProperties: false, }), async execute() { return { id: "code-block-1", code: "console.log('hello');", language: "javascript", filename: "hello.js", highlightLines: [1], }; },});// Frontend with assistant-uiimport { type Toolkit } from "@assistant-ui/react";import { CodeBlock } from "@/components/tool-ui/code-block";import { safeParseSerializableCodeBlock } from "@/components/tool-ui/code-block/schema";import { createResultToolRenderer } from "@/components/tool-ui/shared";export const toolkit: Toolkit = { showCodeBlock: { type: "backend", render: createResultToolRenderer({ safeParse: safeParseSerializableCodeBlock, render: (parsedResult) => ( <CodeBlock {...parsedResult} /> ), }), },};Shiki-powered with 100+ languages
Draw attention to specific lines for explanations or diffs
Opt-in collapse for long snippets via maxCollapsedLines
Filename and language badge in the header
Prop
Type
Prop
Type
Prop
Type
Use ToolUI.LocalActions to compose external actions next to CodeBlock.
CodeBlock supports all languages included with Shiki, including:
See Shiki documentation for the complete list.