Code Block

PreviousNext

Display code with syntax highlighting and copy functionality.

greet.ts
function greet(name: string) {  return `Hello, ${name}!`;}const message = greet("World");console.log(message);
"use client"

import {
  CodeBlock,
  CodeBlockBody,
  CodeBlockContent,
  CodeBlockCopyButton,
  CodeBlockFilename,
  CodeBlockHeader,
  CodeBlockItem,
} from "@/components/ai-elements/code-block"

export function CodeBlockDemo() {
  const codeData = [
    {
      language: "typescript",
      filename: "greet.ts",
      code: `function greet(name: string) {
  return \`Hello, \${name}!\`;
}

const message = greet("World");
console.log(message);`,
    },
  ]

  return (
    <CodeBlock data={codeData} defaultValue="typescript">
      <CodeBlockHeader>
        <CodeBlockFilename value="typescript">
          {codeData[0].filename}
        </CodeBlockFilename>
        <CodeBlockCopyButton />
      </CodeBlockHeader>
      <CodeBlockBody>
        {(item) => (
          <CodeBlockItem key={item.language} value={item.language}>
            <CodeBlockContent language={item.language as any}>
              {item.code}
            </CodeBlockContent>
          </CodeBlockItem>
        )}
      </CodeBlockBody>
    </CodeBlock>
  )
}

Installation

pnpm dlx shadcn@latest add code-block

Usage

import {
  CodeBlock,
  CodeBlockBody,
  CodeBlockContent,
  CodeBlockCopyButton,
  CodeBlockFilename,
  CodeBlockHeader,
  CodeBlockItem,
} from "@/ai-elements/code-block"
const codeData = [
  {
    language: "typescript",
    filename: "example.ts",
    code: `function greet(name: string) {
  return \`Hello, \${name}!\`;
}`,
  },
]
 
<CodeBlock data={codeData} defaultValue="typescript">
  <CodeBlockHeader>
    <CodeBlockFilename value="typescript">
      {codeData[0].filename}
    </CodeBlockFilename>
    <CodeBlockCopyButton />
  </CodeBlockHeader>
  <CodeBlockBody>
    {(item) => (
      <CodeBlockItem key={item.language} value={item.language}>
        <CodeBlockContent language={item.language}>
          {item.code}
        </CodeBlockContent>
      </CodeBlockItem>
    )}
  </CodeBlockBody>
</CodeBlock>

Features

  • Syntax highlighting powered by Shiki
  • Line numbers
  • Copy to clipboard functionality
  • Support for filenames with auto-detected icons
  • Highlighted lines and words
  • Focused lines
  • Diff annotations
  • Language detection
  • Theme support
  • Customizable styles

Examples

No Header

function MyComponent(props) {  return (    <div>      <h1>Hello, {props.name}!</h1>      <p>This is an example React component.</p>    </div>  );}
"use client"

import {
  CodeBlock,
  CodeBlockBody,
  CodeBlockContent,
  CodeBlockItem,
} from "@/components/ai-elements/code-block"

export function CodeBlockNoHeaderDemo() {
  const codeData = [
    {
      language: "jsx",
      filename: "MyComponent.jsx",
      code: `function MyComponent(props) {
  return (
    <div>
      <h1>Hello, {props.name}!</h1>
      <p>This is an example React component.</p>
    </div>
  );
}`,
    },
  ]

  return (
    <CodeBlock data={codeData} defaultValue="jsx">
      <CodeBlockBody>
        {(item) => (
          <CodeBlockItem key={item.language} value={item.language}>
            <CodeBlockContent language={item.language as any}>
              {item.code}
            </CodeBlockContent>
          </CodeBlockItem>
        )}
      </CodeBlockBody>
    </CodeBlock>
  )
}
<CodeBlock data={codeData} defaultValue="jsx">
  <CodeBlockBody>
    {(item) => (
      <CodeBlockItem key={item.language} value={item.language}>
        <CodeBlockContent language={item.language}>
          {item.code}
        </CodeBlockContent>
      </CodeBlockItem>
    )}
  </CodeBlockBody>
</CodeBlock>

Highlighted Lines

MyComponent.jsx
function MyComponent(props) { // [!code highlight]  return (    <div>      <h1>Hello, {props.name}!</h1> // [!code highlight]      <p>This is an example React component.</p>    </div>  );}
"use client"

import {
  CodeBlock,
  CodeBlockBody,
  CodeBlockContent,
  CodeBlockCopyButton,
  CodeBlockFilename,
  CodeBlockHeader,
  CodeBlockItem,
} from "@/components/ai-elements/code-block"

export function CodeBlockHighlightDemo() {
  const codeData = [
    {
      language: "jsx",
      filename: "MyComponent.jsx",
      code: `function MyComponent(props) { // [!code highlight]
  return (
    <div>
      <h1>Hello, {props.name}!</h1> // [!code highlight]
      <p>This is an example React component.</p>
    </div>
  );
}`,
    },
  ]

  return (
    <CodeBlock data={codeData} defaultValue="jsx">
      <CodeBlockHeader>
        <CodeBlockFilename value="jsx">
          {codeData[0].filename}
        </CodeBlockFilename>
        <CodeBlockCopyButton />
      </CodeBlockHeader>
      <CodeBlockBody>
        {(item) => (
          <CodeBlockItem key={item.language} value={item.language}>
            <CodeBlockContent language={item.language as any}>
              {item.code}
            </CodeBlockContent>
          </CodeBlockItem>
        )}
      </CodeBlockBody>
    </CodeBlock>
  )
}

Add // [!code highlight] at the end of lines you want to highlight.

const code = `function MyComponent(props) { // [!code highlight]
  return (
    <div>
      <h1>Hello, {props.name}!</h1> // [!code highlight]
      <p>This is an example React component.</p>
    </div>
  );
}`

Highlighted Words

MyComponent.jsx
function MyComponent(props) {  return (    <div>      // [!code word:props.name]      <h1>Hello, {props.name}!</h1>      <p>This is an example React component.</p>    </div>  );}
"use client"

import {
  CodeBlock,
  CodeBlockBody,
  CodeBlockContent,
  CodeBlockCopyButton,
  CodeBlockFilename,
  CodeBlockHeader,
  CodeBlockItem,
} from "@/components/ai-elements/code-block"

export function CodeBlockHighlightWordDemo() {
  const codeData = [
    {
      language: "jsx",
      filename: "MyComponent.jsx",
      code: `function MyComponent(props) {
  return (
    <div>
      // [!code word:props.name]
      <h1>Hello, {props.name}!</h1>
      <p>This is an example React component.</p>
    </div>
  );
}`,
    },
  ]

  return (
    <CodeBlock data={codeData} defaultValue="jsx">
      <CodeBlockHeader>
        <CodeBlockFilename value="jsx">
          {codeData[0].filename}
        </CodeBlockFilename>
        <CodeBlockCopyButton />
      </CodeBlockHeader>
      <CodeBlockBody>
        {(item) => (
          <CodeBlockItem key={item.language} value={item.language}>
            <CodeBlockContent language={item.language as any}>
              {item.code}
            </CodeBlockContent>
          </CodeBlockItem>
        )}
      </CodeBlockBody>
    </CodeBlock>
  )
}

Add // [!code word:text] to highlight specific words in your code.

const code = `function MyComponent(props) {
  return (
    <div>
      // [!code word:props.name]
      <h1>Hello, {props.name}!</h1>
      <p>This is an example React component.</p>
    </div>
  );
}`

Diff

utils.js
function calculateTotal(items) {  let total = 0;  for (let i = 0; i < items.length; i++) {    total += items[i].price * items[i].quantity; // [!code --]    const itemTotal = items[i].price * items[i].quantity; // [!code ++]    total += itemTotal; // [!code ++]  }  return total;}
"use client"

import {
  CodeBlock,
  CodeBlockBody,
  CodeBlockContent,
  CodeBlockCopyButton,
  CodeBlockFilename,
  CodeBlockHeader,
  CodeBlockItem,
} from "@/components/ai-elements/code-block"

export function CodeBlockDiffDemo() {
  const codeData = [
    {
      language: "javascript",
      filename: "utils.js",
      code: `function calculateTotal(items) {
  let total = 0;
  for (let i = 0; i < items.length; i++) {
    total += items[i].price * items[i].quantity; // [!code --]
    const itemTotal = items[i].price * items[i].quantity; // [!code ++]
    total += itemTotal; // [!code ++]
  }
  return total;
}`,
    },
  ]

  return (
    <CodeBlock data={codeData} defaultValue="javascript">
      <CodeBlockHeader>
        <CodeBlockFilename value="javascript">
          {codeData[0].filename}
        </CodeBlockFilename>
        <CodeBlockCopyButton />
      </CodeBlockHeader>
      <CodeBlockBody>
        {(item) => (
          <CodeBlockItem key={item.language} value={item.language}>
            <CodeBlockContent language={item.language as any}>
              {item.code}
            </CodeBlockContent>
          </CodeBlockItem>
        )}
      </CodeBlockBody>
    </CodeBlock>
  )
}

Use // [!code --] for deletions and // [!code ++] for additions.

const code = `function calculateTotal(items) {
  let total = 0;
  for (let i = 0; i < items.length; i++) {
    total += items[i].price * items[i].quantity; // [!code --]
    const itemTotal = items[i].price * items[i].quantity; // [!code ++]
    total += itemTotal; // [!code ++]
  }
  return total;
}`

Focus

utils.js
function calculateDiscount(price, percentage) {  const discount = price * (percentage / 100); // [!code focus]  return price - discount;}// Example usageconst finalPrice = calculateDiscount(100, 20);console.log(finalPrice); // 80
"use client"

import {
  CodeBlock,
  CodeBlockBody,
  CodeBlockContent,
  CodeBlockCopyButton,
  CodeBlockFilename,
  CodeBlockHeader,
  CodeBlockItem,
} from "@/components/ai-elements/code-block"

export function CodeBlockFocusDemo() {
  const codeData = [
    {
      language: "javascript",
      filename: "utils.js",
      code: `function calculateDiscount(price, percentage) {
  const discount = price * (percentage / 100); // [!code focus]
  return price - discount;
}

// Example usage
const finalPrice = calculateDiscount(100, 20);
console.log(finalPrice); // 80`,
    },
  ]

  return (
    <CodeBlock data={codeData} defaultValue="javascript">
      <CodeBlockHeader>
        <CodeBlockFilename value="javascript">
          {codeData[0].filename}
        </CodeBlockFilename>
        <CodeBlockCopyButton />
      </CodeBlockHeader>
      <CodeBlockBody>
        {(item) => (
          <CodeBlockItem key={item.language} value={item.language}>
            <CodeBlockContent language={item.language as any}>
              {item.code}
            </CodeBlockContent>
          </CodeBlockItem>
        )}
      </CodeBlockBody>
    </CodeBlock>
  )
}

Use // [!code focus] to focus on specific lines while blurring the rest.

const code = `function calculateDiscount(price, percentage) {
  const discount = price * (percentage / 100); // [!code focus]
  return price - discount;
}
 
// Example usage
const finalPrice = calculateDiscount(100, 20);
console.log(finalPrice); // 80`

Hidden Line Numbers

MyComponent.jsx
function MyComponent(props) {  return (    <div>      <h1>Hello, {props.name}!</h1>      <p>This is an example React component.</p>    </div>  );}
"use client"

import {
  CodeBlock,
  CodeBlockBody,
  CodeBlockContent,
  CodeBlockCopyButton,
  CodeBlockFilename,
  CodeBlockHeader,
  CodeBlockItem,
} from "@/components/ai-elements/code-block"

export function CodeBlockNoLineNumbersDemo() {
  const codeData = [
    {
      language: "jsx",
      filename: "MyComponent.jsx",
      code: `function MyComponent(props) {
  return (
    <div>
      <h1>Hello, {props.name}!</h1>
      <p>This is an example React component.</p>
    </div>
  );
}`,
    },
  ]

  return (
    <CodeBlock data={codeData} defaultValue="jsx">
      <CodeBlockHeader>
        <CodeBlockFilename value="jsx">
          {codeData[0].filename}
        </CodeBlockFilename>
        <CodeBlockCopyButton />
      </CodeBlockHeader>
      <CodeBlockBody>
        {(item) => (
          <CodeBlockItem
            key={item.language}
            value={item.language}
            lineNumbers={false}
          >
            <CodeBlockContent language={item.language as any}>
              {item.code}
            </CodeBlockContent>
          </CodeBlockItem>
        )}
      </CodeBlockBody>
    </CodeBlock>
  )
}

Set lineNumbers={false} on the CodeBlockItem component.

<CodeBlockItem key={item.language} value={item.language} lineNumbers={false}>
  <CodeBlockContent language={item.language}>
    {item.code}
  </CodeBlockContent>
</CodeBlockItem>

No Syntax Highlighting

MyComponent.jsx
function MyComponent(props) {  return (    <div>      <h1>Hello, {props.name}!</h1>      <p>This is an example React component.</p>    </div>  );}
"use client"

import {
  CodeBlock,
  CodeBlockBody,
  CodeBlockContent,
  CodeBlockCopyButton,
  CodeBlockFilename,
  CodeBlockHeader,
  CodeBlockItem,
} from "@/components/ai-elements/code-block"

export function CodeBlockNoSyntaxDemo() {
  const codeData = [
    {
      language: "jsx",
      filename: "MyComponent.jsx",
      code: `function MyComponent(props) {
  return (
    <div>
      <h1>Hello, {props.name}!</h1>
      <p>This is an example React component.</p>
    </div>
  );
}`,
    },
  ]

  return (
    <CodeBlock data={codeData} defaultValue="jsx">
      <CodeBlockHeader>
        <CodeBlockFilename value="jsx">
          {codeData[0].filename}
        </CodeBlockFilename>
        <CodeBlockCopyButton />
      </CodeBlockHeader>
      <CodeBlockBody>
        {(item) => (
          <CodeBlockItem key={item.language} value={item.language}>
            <CodeBlockContent
              language={item.language as any}
              syntaxHighlighting={false}
            >
              {item.code}
            </CodeBlockContent>
          </CodeBlockItem>
        )}
      </CodeBlockBody>
    </CodeBlock>
  )
}

Set syntaxHighlighting={false} on the CodeBlockContent component.

<CodeBlockContent language={item.language} syntaxHighlighting={false}>
  {item.code}
</CodeBlockContent>

Custom Theme

MyComponent.jsx
function MyComponent(props) {  return (    <div>      <h1>Hello, {props.name}!</h1>      <p>This is an example React component.</p>    </div>  );}
"use client"

import {
  CodeBlock,
  CodeBlockBody,
  CodeBlockContent,
  CodeBlockCopyButton,
  CodeBlockFilename,
  CodeBlockHeader,
  CodeBlockItem,
} from "@/components/ai-elements/code-block"

export function CodeBlockCustomThemeDemo() {
  const codeData = [
    {
      language: "jsx",
      filename: "MyComponent.jsx",
      code: `function MyComponent(props) {
  return (
    <div>
      <h1>Hello, {props.name}!</h1>
      <p>This is an example React component.</p>
    </div>
  );
}`,
    },
  ]

  return (
    <CodeBlock data={codeData} defaultValue="jsx">
      <CodeBlockHeader>
        <CodeBlockFilename value="jsx">
          {codeData[0].filename}
        </CodeBlockFilename>
        <CodeBlockCopyButton />
      </CodeBlockHeader>
      <CodeBlockBody>
        {(item) => (
          <CodeBlockItem key={item.language} value={item.language}>
            <CodeBlockContent
              language={item.language as any}
              themes={{
                light: "vitesse-light",
                dark: "vitesse-dark",
              }}
            >
              {item.code}
            </CodeBlockContent>
          </CodeBlockItem>
        )}
      </CodeBlockBody>
    </CodeBlock>
  )
}

Pass custom themes to the CodeBlockContent component using the themes prop.

<CodeBlockContent
  language={item.language}
  themes={{
    light: "vitesse-light",
    dark: "vitesse-dark",
  }}
>
  {item.code}
</CodeBlockContent>

Multiple Files

Button.tsx
import { type ReactNode } from "react"interface ButtonProps {  children: ReactNode  onClick?: () => void  variant?: "primary" | "secondary"}export function Button({ children, onClick, variant = "primary" }: ButtonProps) {  return (    <button      onClick={onClick}      className={`btn btn-${variant}`}    >      {children}    </button>  )}
"use client"

import {
  CodeBlock,
  CodeBlockBody,
  CodeBlockContent,
  CodeBlockCopyButton,
  CodeBlockFilename,
  CodeBlockFiles,
  CodeBlockHeader,
  CodeBlockItem,
  CodeBlockSelect,
  CodeBlockSelectItem,
} from "@/components/ai-elements/code-block"

export function CodeBlockMultipleFilesDemo() {
  const codeData = [
    {
      language: "typescript",
      filename: "Button.tsx",
      code: `import { type ReactNode } from "react"

interface ButtonProps {
  children: ReactNode
  onClick?: () => void
  variant?: "primary" | "secondary"
}

export function Button({ children, onClick, variant = "primary" }: ButtonProps) {
  return (
    <button
      onClick={onClick}
      className={\`btn btn-\${variant}\`}
    >
      {children}
    </button>
  )
}`,
    },
    {
      language: "typescript",
      filename: "Input.tsx",
      code: `import { type InputHTMLAttributes } from "react"

interface InputProps extends InputHTMLAttributes<HTMLInputElement> {
  label?: string
  error?: string
}

export function Input({ label, error, ...props }: InputProps) {
  return (
    <div className="input-wrapper">
      {label && <label>{label}</label>}
      <input {...props} />
      {error && <span className="error">{error}</span>}
    </div>
  )
}`,
    },
    {
      language: "css",
      filename: "styles.css",
      code: `.btn {
  padding: 0.5rem 1rem;
  border-radius: 0.375rem;
  font-weight: 500;
  transition: all 0.2s;
}

.btn-primary {
  background-color: #3b82f6;
  color: white;
}

.btn-secondary {
  background-color: #6b7280;
  color: white;
}`,
    },
  ]

  return (
    <CodeBlock data={codeData} defaultValue={codeData[0].filename}>
      <CodeBlockHeader>
        <CodeBlockFiles>
          {(item) => (
            <CodeBlockFilename key={item.filename} value={item.filename}>
              {item.filename}
            </CodeBlockFilename>
          )}
        </CodeBlockFiles>
        <CodeBlockSelect>
          {(item) => (
            <CodeBlockSelectItem key={item.filename} id={item.filename}>
              {item.filename}
            </CodeBlockSelectItem>
          )}
        </CodeBlockSelect>
        <CodeBlockCopyButton
          onCopy={() => console.log("Copied code to clipboard")}
          onError={() => console.error("Failed to copy code to clipboard")}
        />
      </CodeBlockHeader>
      <CodeBlockBody>
        {(item) => (
          <CodeBlockItem key={item.filename} value={item.filename}>
            <CodeBlockContent language={item.language as any}>
              {item.code}
            </CodeBlockContent>
          </CodeBlockItem>
        )}
      </CodeBlockBody>
    </CodeBlock>
  )
}

Use CodeBlockSelect to switch between multiple files.

const codeData = [
  {
    language: "typescript",
    filename: "Button.tsx",
    code: `...`,
  },
  {
    language: "typescript",
    filename: "Input.tsx",
    code: `...`,
  },
  {
    language: "css",
    filename: "styles.css",
    code: `...`,
  },
]
 
<CodeBlock data={codeData} defaultValue="typescript">
  <CodeBlockHeader>
    <CodeBlockSelect>
      {(item) => (
        <CodeBlockSelectItem key={item.language} id={item.language}>
          {item.filename}
        </CodeBlockSelectItem>
      )}
    </CodeBlockSelect>
    <CodeBlockCopyButton />
  </CodeBlockHeader>
  <CodeBlockBody>
    {(item) => (
      <CodeBlockItem key={item.language} value={item.language}>
        <CodeBlockContent language={item.language}>
          {item.code}
        </CodeBlockContent>
      </CodeBlockItem>
    )}
  </CodeBlockBody>
</CodeBlock>