Code Block

Use the shorthand with code or tabs, or compose Header, List, Actions, and Content yourself. Copy copies the raw source of the active tab.

const greet = (name: string) => {
  return `Hello, ${name}!`;
};
<script lang="ts">
    import * as CodeBlock from '@sivir-ui/svelte/components/code-block';

    const code = `const greet = (name: string) => {
  return \`Hello, \${name}!\`;
};`;
</script>

<CodeBlock.Root value="ts">
    <CodeBlock.Content value="ts" {code} lang="typescript" />
</CodeBlock.Root>

Installation

Copy the command below and run it in your terminal.

bunx @sivir-ui/svelte add code-block

The component depends on highlight.js. Install it if your project doesn't have it yet:

Copy the command below and run it in your terminal.

bun add highlight.js

Usage

Pass code and lang for one snippet, or a tabs array for several. Root's value picks the open tab by matching each tab's value, which defaults to its lang. It is bindable and starts on the first tab.

import { CodeBlock } from '@sivir-ui/svelte/components/code-block';

<CodeBlock
  value="javascript"
  tabs={[
    { label: 'Python',     lang: 'python',     code: pyCode },
    { label: 'JavaScript', lang: 'javascript', code: jsCode },
  ]}
/>

The default theme colors tokens with GitHub light and GitHub dark, and theme presets set their own palette. To use a highlight.js theme instead, set theme="custom" and load its stylesheet. The component then skips its own token colors.

import 'highlight.js/styles/github-dark.css';
import { CodeBlock } from '@sivir-ui/svelte/components/code-block';

<CodeBlock code={code} lang="typescript" theme="custom" />

Examples

Single snippet

const greet = (name: string) => {
  return `Hello, ${name}!`;
};

console.log(greet('world'));
<script lang="ts">
    import * as CodeBlock from '@sivir-ui/svelte/components/code-block';

    const code = `const greet = (name: string) => {
  return \`Hello, \${name}!\`;
};

console.log(greet('world'));`;
</script>

<CodeBlock.Root value="ts">
    <CodeBlock.Content value="ts" {code} lang="typescript" />
</CodeBlock.Root>

Multiple languages

export async function getUser(id: string) {
  const res = await fetch(`/api/users/${id}`);
  if (!res.ok) throw new Error('Not found');
  return res.json();
}
<script lang="ts">
    import { CodeBlock } from '@sivir-ui/svelte/components/code-block';

    const ts = `export async function getUser(id: string) {
  const res = await fetch(\`/api/users/\${id}\`);
  if (!res.ok) throw new Error('Not found');
  return res.json();
}`;

    const py = `import httpx

async def get_user(id: str):
    async with httpx.AsyncClient() as client:
        res = await client.get(f"/api/users/{id}")
        res.raise_for_status()
        return res.json()`;

    const go = `func GetUser(id string) (*User, error) {
    res, err := http.Get("/api/users/" + id)
    if err != nil {
        return nil, err
    }
    defer res.Body.Close()
    return decode(res.Body)
}`;
</script>

<CodeBlock
    class="max-w-xl"
    value="typescript"
    tabs={[
        { label: 'TypeScript', lang: 'typescript', code: ts },
        { label: 'Python', lang: 'python', code: py },
        { label: 'Go', lang: 'go', code: go }
    ]}
/>

Line numbers

def fib(n):
    a, b = 0, 1
    for _ in range(n):
        a, b = b, a + b
    return a

print([fib(i) for i in range(10)])
<script lang="ts">
    import * as CodeBlock from '@sivir-ui/svelte/components/code-block';

    const code = `def fib(n):
    a, b = 0, 1
    for _ in range(n):
        a, b = b, a + b
    return a

print([fib(i) for i in range(10)])`;
</script>

<CodeBlock.Root value="py">
    <CodeBlock.Content value="py" {code} lang="python" showLineNumbers />
</CodeBlock.Root>

Custom actions

SELECT id, email, created_at
FROM users
WHERE created_at > now() - interval '7 days'
ORDER BY created_at DESC
LIMIT 50;
<script lang="ts">
    import ExternalLink from '@lucide/svelte/icons/external-link';
    import RefreshCw from '@lucide/svelte/icons/refresh-cw';
    import { Button } from '@sivir-ui/svelte/components/button';
    import * as CodeBlock from '@sivir-ui/svelte/components/code-block';
    import * as Tooltip from '@sivir-ui/svelte/components/tooltip';

    const code = `SELECT id, email, created_at
FROM users
WHERE created_at > now() - interval '7 days'
ORDER BY created_at DESC
LIMIT 50;`;
</script>

<CodeBlock.Root value="sql">
    <CodeBlock.Header>
        <CodeBlock.Actions>
            <Tooltip.Root>
                <Tooltip.Trigger>
                    <Button variant="ghost" size="icon" aria-label="Run query">
                        <RefreshCw size={15} />
                    </Button>
                </Tooltip.Trigger>
                <Tooltip.Content>Run query</Tooltip.Content>
            </Tooltip.Root>
            <Tooltip.Root>
                <Tooltip.Trigger>
                    <Button variant="ghost" size="icon" aria-label="Open in editor">
                        <ExternalLink size={15} />
                    </Button>
                </Tooltip.Trigger>
                <Tooltip.Content>Open in editor</Tooltip.Content>
            </Tooltip.Root>
        </CodeBlock.Actions>
    </CodeBlock.Header>
    <CodeBlock.Content value="sql" {code} lang="sql" />
</CodeBlock.Root>

Copy placement: overlay

model = SentenceTransformer("all-MiniLM-L6-v2")
embeddings = model.encode(documents)
index.upsert(vectors=zip(ids, embeddings))
<script lang="ts">
    import * as CodeBlock from '@sivir-ui/svelte/components/code-block';

    const code = `model = SentenceTransformer("all-MiniLM-L6-v2")
embeddings = model.encode(documents)
index.upsert(vectors=zip(ids, embeddings))`;
</script>

<!-- copyPlacement="overlay" pins the copy button to the body's top-right (no header). -->
<CodeBlock.Root value="py">
    <CodeBlock.Content value="py" {code} lang="python" copyPlacement="overlay" />
</CodeBlock.Root>

Copy placement: inline

bunx @sivir-ui/svelte add code-block
<script lang="ts">
    import * as CodeBlock from '@sivir-ui/svelte/components/code-block';
</script>

<!-- copyPlacement="inline": a single-line body with the copy centered on the far right. -->
<CodeBlock.Root value="sh">
    <CodeBlock.Content
        value="sh"
        code="bunx @sivir-ui/svelte add code-block"
        lang="bash"
        copyPlacement="inline"
    />
</CodeBlock.Root>

Anatomy

CodeBlock.Root - Provides code block state and layout.

CodeBlock.Header - Renders the code block header.

CodeBlock.List - Groups code language tabs.

CodeBlock.Trigger - Selects a code language tab.

CodeBlock.Actions - Groups code block actions.

CodeBlock.Copy - Copies the active code snippet.

CodeBlock.Content - Renders a code snippet panel.

CodeBlock - Renders a high-level code block.