# Code Block

```tsx
"use client"

import { CodeBlock, createShikiAdapter } from "@chakra-ui/react"
import type { HighlighterGeneric } from "shiki"

const file = {
  code: `
<div class="container">
  <h1>Hello, world!</h1>
</div>
`,
  language: "html",
  title: "index.html",
}

export const CodeBlockBasic = () => {
  return (
    <CodeBlock.AdapterProvider value={shikiAdapter}>
      <CodeBlock.Root code={file.code} language={file.language}>
        <CodeBlock.Content>
          <CodeBlock.Code>
            <CodeBlock.CodeText />
          </CodeBlock.Code>
        </CodeBlock.Content>
      </CodeBlock.Root>
    </CodeBlock.AdapterProvider>
  )
}

const shikiAdapter = createShikiAdapter<HighlighterGeneric<any, any>>({
  async load() {
    const { createHighlighter } = await import("shiki")
    return createHighlighter({
      langs: ["tsx", "scss", "html", "bash", "json"],
      themes: ["github-dark"],
    })
  },
  theme: "github-dark",
})

```

## Usage

```js
import { CodeBlock } from "@chakra-ui/react"
```

```jsx
<CodeBlock.AdapterProvider>
  <CodeBlock.Root>
    <CodeBlock.Header>
      <CodeBlock.Title />
      <CodeBlock.Control>
        <CodeBlock.CopyTrigger />
        <CodeBlock.CollapseTrigger />
      </CodeBlock.Control>
    </CodeBlock.Header>
    <CodeBlock.Content>
      <CodeBlock.Code>
        <CodeBlock.CodeText />
      </CodeBlock.Code>
    </CodeBlock.Content>
  </CodeBlock.Root>
</CodeBlock.AdapterProvider>
```

## Adapters

The CodeBlock component works for [Shiki](https://shiki.style/) and
[Highlight.js](https://highlightjs.org/) highlighting engines.

> The docs assumes **Shiki** by default.

To setup the code block component, you need to:

- Configure your preferred adapter (**Shiki** or **Highlight.js**).
- Provide the adapter to the `CodeBlock.AdapterProvider` at the top level.
- Render the `CodeBlock.Root` component within the `CodeBlock.AdapterProvider`.

### Shiki

Install the `shiki` package.

```bash
npm install shiki
```

Then, create the shiki adapter that dynamically loads the shiki highlighter for
the selected languages.

```tsx
import type { HighlighterGeneric } from "shiki"
import { createShikiAdapter } from "@chakra-ui/react"

const shikiAdapter = createShikiAdapter<HighlighterGeneric<any, any>>({
  async load() {
    const { createHighlighter } = await import("shiki")
    return createHighlighter({
      langs: ["tsx", "json"],
      themes: ["github-dark", "github-light"],
    })
  },
})

<CodeBlock.AdapterProvider value={shikiAdapter}>
  {/* ... */}
</CodeBlock.AdapterProvider>
```

### Highlight.js

Install the `highlight.js` package.

```bash
npm install highlight.js
```

Then, create the highlight.js adapter that dynamically loads the selected
languages.

```tsx
import { createHighlightJsAdapter } from "@chakra-ui/react"
import hljs from "highlight.js/lib/core"

const highlightJsAdapter = createHighlightJsAdapter<typeof hljs>({
  async load() {
    const languages = {
      tsx: () => import("highlight.js/lib/languages/typescript"),
      html: () => import("highlight.js/lib/languages/xml"),
    }
    await Promise.all(
      Object.entries(languages).map(async ([language, file]) => {
        const { default: langModule } = await file()
        hljs.registerLanguage(language, langModule)
      }),
    )
    return hljs
  },
})
```

## Examples

### Sizes

Use the `size` prop to change the size of the code block component.

```tsx
"use client"

import { CodeBlock, For, Stack, createShikiAdapter } from "@chakra-ui/react"
import type { HighlighterGeneric } from "shiki"

const file = {
  code: `
<div class="container">
  <h1>Hello, world!</h1>
</div>
`,
  language: "html",
  title: "index.html",
}

export const CodeBlockWithSizes = () => {
  return (
    <CodeBlock.AdapterProvider value={shikiAdapter}>
      <Stack gap="8">
        <For each={["sm", "md", "lg"]}>
          {(size) => (
            <CodeBlock.Root
              key={size}
              code={file.code}
              language={file.language}
              size={size}
            >
              <CodeBlock.Header>
                <CodeBlock.Title>(size={size})</CodeBlock.Title>
              </CodeBlock.Header>
              <CodeBlock.Content>
                <CodeBlock.Code>
                  <CodeBlock.CodeText />
                </CodeBlock.Code>
              </CodeBlock.Content>
            </CodeBlock.Root>
          )}
        </For>
      </Stack>
    </CodeBlock.AdapterProvider>
  )
}

const shikiAdapter = createShikiAdapter<HighlighterGeneric<any, any>>({
  async load() {
    const { createHighlighter } = await import("shiki")
    return createHighlighter({
      langs: ["tsx", "scss", "html", "bash", "json"],
      themes: ["github-dark"],
    })
  },
  theme: "github-dark",
})

```

### Title

Render the `CodeBlock.Title` component within the `CodeBlock.Header` component
to add a title to the code block component.

```tsx
"use client"

import { CodeBlock, Icon, createShikiAdapter } from "@chakra-ui/react"
import { FaHtml5 } from "react-icons/fa"
import type { HighlighterGeneric } from "shiki"

const file = {
  code: `
<div class="container">
  <h1>Hello, world!</h1>
</div>
`,
  language: "html",
  title: "index.html",
}

export const CodeBlockWithTitle = () => {
  return (
    <CodeBlock.AdapterProvider value={shikiAdapter}>
      <CodeBlock.Root code={file.code} language={file.language}>
        <CodeBlock.Header>
          <CodeBlock.Title>
            <Icon as={FaHtml5} color="orange.300" />
            {file.title}
          </CodeBlock.Title>
        </CodeBlock.Header>
        <CodeBlock.Content>
          <CodeBlock.Code>
            <CodeBlock.CodeText />
          </CodeBlock.Code>
        </CodeBlock.Content>
      </CodeBlock.Root>
    </CodeBlock.AdapterProvider>
  )
}

const shikiAdapter = createShikiAdapter<HighlighterGeneric<any, any>>({
  async load() {
    const { createHighlighter } = await import("shiki")
    return createHighlighter({
      langs: ["tsx", "scss", "html", "bash", "json"],
      themes: ["github-dark"],
    })
  },
  theme: "github-dark",
})

```

### Copy button

Use the `copyButton` prop to add a copy button to the code block component.

```tsx
"use client"

import { CodeBlock, IconButton, createShikiAdapter } from "@chakra-ui/react"
import type { HighlighterGeneric } from "shiki"

const file = {
  code: `
<div class="container">
  <h1>Hello, world!</h1>
</div>
`,
  language: "html",
  title: "index.html",
}

export const CodeBlockWithCopyButton = () => {
  return (
    <CodeBlock.AdapterProvider value={shikiAdapter}>
      <CodeBlock.Root code={file.code} language={file.language}>
        <CodeBlock.Header>
          <CodeBlock.Title>{file.title}</CodeBlock.Title>
          <CodeBlock.CopyTrigger asChild>
            <IconButton variant="ghost" size="2xs">
              <CodeBlock.CopyIndicator />
            </IconButton>
          </CodeBlock.CopyTrigger>
        </CodeBlock.Header>
        <CodeBlock.Content>
          <CodeBlock.Code>
            <CodeBlock.CodeText />
          </CodeBlock.Code>
        </CodeBlock.Content>
      </CodeBlock.Root>
    </CodeBlock.AdapterProvider>
  )
}

const shikiAdapter = createShikiAdapter<HighlighterGeneric<any, any>>({
  async load() {
    const { createHighlighter } = await import("shiki")
    return createHighlighter({
      langs: ["tsx", "scss", "html", "bash", "json"],
      themes: ["github-dark"],
    })
  },
  theme: "github-dark",
})

```

### Line numbers

Line numbers make it easier to reference specific lines of code. Pass the
`meta.showLineNumbers` prop to show line numbers in the code block component.

```tsx
"use client"

import { CodeBlock, createShikiAdapter } from "@chakra-ui/react"
import type { HighlighterGeneric } from "shiki"

const file = {
  code: `
<div class="container">
  <h1>Hello, world!</h1>
</div>
`,
  language: "html",
  title: "index.html",
}

export const CodeBlockWithLineNumbers = () => {
  return (
    <CodeBlock.AdapterProvider value={shikiAdapter}>
      <CodeBlock.Root
        code={file.code}
        language={file.language}
        meta={{ showLineNumbers: true }}
      >
        <CodeBlock.Content>
          <CodeBlock.Code>
            <CodeBlock.CodeText />
          </CodeBlock.Code>
        </CodeBlock.Content>
      </CodeBlock.Root>
    </CodeBlock.AdapterProvider>
  )
}

const shikiAdapter = createShikiAdapter<HighlighterGeneric<any, any>>({
  async load() {
    const { createHighlighter } = await import("shiki")
    return createHighlighter({
      langs: ["tsx", "scss", "html", "bash", "json"],
      themes: ["github-dark"],
    })
  },
  theme: "github-dark",
})

```

### Line highlighting

Pass the `meta.highlightLines` prop to the `CodeBlock.Root` component to
highlight specific lines of code. The prop accepts an array of line numbers.

```tsx
"use client"

import { CodeBlock, createShikiAdapter } from "@chakra-ui/react"
import type { HighlighterGeneric } from "shiki"

const file = {
  code: `
<div class="container">
  <h1>Hello, world!</h1>
</div>
`,
  language: "html",
  title: "index.html",
}

export const CodeBlockWithLineHighlight = () => {
  return (
    <CodeBlock.AdapterProvider value={shikiAdapter}>
      <CodeBlock.Root
        code={file.code}
        language={file.language}
        meta={{ highlightLines: [2, 1] }}
      >
        <CodeBlock.Content>
          <CodeBlock.Code>
            <CodeBlock.CodeText />
          </CodeBlock.Code>
        </CodeBlock.Content>
      </CodeBlock.Root>
    </CodeBlock.AdapterProvider>
  )
}

const shikiAdapter = createShikiAdapter<HighlighterGeneric<any, any>>({
  async load() {
    const { createHighlighter } = await import("shiki")
    return createHighlighter({
      langs: ["tsx", "scss", "html", "bash", "json"],
      themes: ["github-dark"],
    })
  },
  theme: "github-dark",
})

```

### Line focus

Pass the `meta.focusedLineNumbers` prop to the `CodeBlock.Root` component to
focus specific lines of code. The prop accepts an array of line numbers. The
line numbers.

```tsx
"use client"

import { CodeBlock, createShikiAdapter } from "@chakra-ui/react"
import type { HighlighterGeneric } from "shiki"

const file = {
  code: `
const greeting = "Hello, World!"

function sayHello() {
  console.log(greeting);
}

sayHello()
`,
  language: "tsx",
  title: "index.tsx",
}

export const CodeBlockWithLineFocus = () => {
  return (
    <CodeBlock.AdapterProvider value={shikiAdapter}>
      <CodeBlock.Root
        code={file.code}
        language={file.language}
        meta={{ focusedLineNumbers: [3, 7] }}
      >
        <CodeBlock.Content>
          <CodeBlock.Code>
            <CodeBlock.CodeText />
          </CodeBlock.Code>
        </CodeBlock.Content>
      </CodeBlock.Root>
    </CodeBlock.AdapterProvider>
  )
}

const shikiAdapter = createShikiAdapter<HighlighterGeneric<any, any>>({
  async load() {
    const { createHighlighter } = await import("shiki")
    return createHighlighter({
      langs: ["tsx", "scss", "html", "bash", "json"],
      themes: ["github-dark"],
    })
  },
  theme: "github-dark",
})

```

### Diff

Diffs are useful for highlighting source code changes. Use the
`meta.addedLineNumbers` and `meta.removedLineNumbers` props to add line numbers
to the code block component.

> The prop accepts an array of line numbers. The line numbers are 1-based.

```tsx
"use client"

import { CodeBlock, createShikiAdapter } from "@chakra-ui/react"
import type { HighlighterGeneric } from "shiki"

const file = {
  code: `
const greeting = "Hello, World!"; 
function sayHello() {
  console.log("Hello, World!"); 
  console.log(greeting); 
}
sayHello();
`,
  language: "tsx",
  title: "index.tsx",
}

export const CodeBlockWithDiff = () => {
  return (
    <CodeBlock.AdapterProvider value={shikiAdapter}>
      <CodeBlock.Root
        code={file.code}
        language={file.language}
        meta={{
          showLineNumbers: true,
          addedLineNumbers: [4],
          removedLineNumbers: [3],
        }}
      >
        <CodeBlock.Content>
          <CodeBlock.Code>
            <CodeBlock.CodeText />
          </CodeBlock.Code>
        </CodeBlock.Content>
      </CodeBlock.Root>
    </CodeBlock.AdapterProvider>
  )
}

const shikiAdapter = createShikiAdapter<HighlighterGeneric<any, any>>({
  async load() {
    const { createHighlighter } = await import("shiki")
    return createHighlighter({
      langs: ["tsx", "scss", "html", "bash", "json"],
      themes: ["github-dark"],
    })
  },
  theme: "github-dark",
})

```

### Max lines

Use the `meta.maxLines` prop to limit the number of lines in the code block
component. By default, the code block component will expand to fit the content.

```tsx
"use client"

import { CodeBlock, IconButton, createShikiAdapter } from "@chakra-ui/react"
import type { HighlighterGeneric } from "shiki"

export const CodeBlockWithMaxLines = () => {
  return (
    <CodeBlock.AdapterProvider value={shikiAdapter}>
      <CodeBlock.Root code={file.code} language={file.language} maxLines={10}>
        <CodeBlock.Header>
          <CodeBlock.Title>{file.title}</CodeBlock.Title>
          <CodeBlock.Control>
            <CodeBlock.CollapseTrigger asChild>
              <IconButton variant="ghost" size="2xs">
                <CodeBlock.CollapseIndicator />
              </IconButton>
            </CodeBlock.CollapseTrigger>
            <CodeBlock.CopyTrigger asChild>
              <IconButton variant="ghost" size="2xs">
                <CodeBlock.CopyIndicator />
              </IconButton>
            </CodeBlock.CopyTrigger>
          </CodeBlock.Control>
        </CodeBlock.Header>
        <CodeBlock.Content>
          <CodeBlock.Code>
            <CodeBlock.CodeText />
          </CodeBlock.Code>

          <CodeBlock.Overlay>
            <CodeBlock.CollapseTrigger>
              <CodeBlock.CollapseText textStyle="sm" />
            </CodeBlock.CollapseTrigger>
          </CodeBlock.Overlay>
        </CodeBlock.Content>
      </CodeBlock.Root>
    </CodeBlock.AdapterProvider>
  )
}

const shikiAdapter = createShikiAdapter<HighlighterGeneric<any, any>>({
  async load() {
    const { createHighlighter } = await import("shiki")
    return createHighlighter({
      langs: ["tsx", "scss", "html", "bash", "json"],
      themes: ["github-dark"],
    })
  },
  theme: "github-dark",
})

const file = {
  code: `import * as React from 'react';
import { CodeBlock } from '@chakra-ui/react';

const Example = () => {
  const code = \`
{
  "name": "My App",
  "version": "1.0.0",
  "description": "A simple web application",
  "main": "index.js",
  "scripts": {
    "start": "node server.js",
    "dev": "nodemon server.js",
    "build": "webpack --mode production",
    "test": "jest"
  },
  "dependencies": {
    "express": "^4.18.2",
    "react": "^18.2.0",
    "axios": "^1.4.0"
  },
  "author": "Developer",
  "license": "MIT"
}
  \`

  return (
    <CodeBlock.Root language="json" code={code}>
      <CodeBlock.Header>
        <CodeBlock.Title>{file.title}</CodeBlock.Title>
      </CodeBlock.Header>
    </CodeBlock.Root>
  );
};

export default Example;
`,
  language: "tsx",
  title: "index.tsx",
}

```

### Language switcher

Here's an example that re-creates an API endpoint request component by composing
the `CodeBlock` and `Select` components.

```tsx
"use client"

import {
  Badge,
  CodeBlock,
  HStack,
  Icon,
  IconButton,
  Select,
  Span,
  createListCollection,
  createShikiAdapter,
  useSelect,
} from "@chakra-ui/react"
import { IoLogoJavascript, IoLogoPython } from "react-icons/io5"
import type { HighlighterGeneric } from "shiki"

export const CodeBlockWithLanguageSwitcher = () => {
  const select = useSelect({
    positioning: { strategy: "fixed" },
    defaultValue: [files[0].value],
    collection,
  })

  const selectedFile = select.selectedItems[0]

  return (
    <CodeBlock.AdapterProvider value={shikiAdapter}>
      <CodeBlock.Root
        code={selectedFile.code}
        language={selectedFile.language}
        size="lg"
      >
        <CodeBlock.Header>
          <HStack flex="1">
            <Badge colorPalette="teal" fontWeight="bold">
              POST
            </Badge>
            <Span textStyle="xs">/v1/search</Span>
          </HStack>
          <CodeBlock.Control>
            <LanguageSwitcher value={select} />
            <CodeBlock.CopyTrigger asChild>
              <IconButton variant="ghost" size="2xs">
                <CodeBlock.CopyIndicator />
              </IconButton>
            </CodeBlock.CopyTrigger>
          </CodeBlock.Control>
        </CodeBlock.Header>
        <CodeBlock.Content>
          <CodeBlock.Code fontSize="xs">
            <CodeBlock.CodeText />
          </CodeBlock.Code>
        </CodeBlock.Content>
      </CodeBlock.Root>
    </CodeBlock.AdapterProvider>
  )
}

function LanguageSwitcher(props: Select.RootProviderProps) {
  const { value: select } = props
  return (
    <Select.RootProvider size="xs" variant="subtle" {...props}>
      <Select.Control>
        <Select.Trigger>
          <Select.ValueText />
          <Select.Indicator />
        </Select.Trigger>
      </Select.Control>
      <Select.Positioner>
        <Select.Content>
          {select.collection.items.map((item) => (
            <Select.Item item={item} key={item.value}>
              {item.icon}
              <Select.ItemText>{item.value}</Select.ItemText>
            </Select.Item>
          ))}
        </Select.Content>
      </Select.Positioner>
    </Select.RootProvider>
  )
}

const shikiAdapter = createShikiAdapter<HighlighterGeneric<any, any>>({
  async load() {
    const { createHighlighter } = await import("shiki")
    return createHighlighter({
      langs: ["python", "typescript"],
      themes: ["github-dark"],
    })
  },
  theme: "github-dark",
})

interface CodeFile {
  value: string
  code: string
  language: string
  title: string
  icon: React.ReactElement
}

const files: CodeFile[] = [
  {
    value: "python",
    code: `
from github import Github