CodeBlock

CodeBlock shows a snippet of source code in a dark frame with an optional header for a file name, a language label, custom actions and a copy-to-clipboard button.

import { CodeBlock } from 'jarvis-react-ui';

Basic

Pass the source as code. It is rendered as plain text, so no escaping is needed. The copy button is on by default.

import { CodeBlock } from 'jarvis-react-ui';

export default function Basic() {
    return <CodeBlock code="npm install jarvis-react-ui" />;
}

Title and language

title (usually a file name) and language are shown in the header. The language is only a label; CodeBlock does not highlight code by itself.

import { CodeBlock } from 'jarvis-react-ui';

const SOURCE = `import { Button } from 'jarvis-react-ui';

export function App() {
    return <Button variant="primary">Engage</Button>;
}`;

export default function TitleAndLanguage() {
    return <CodeBlock title="App.tsx" language="tsx" code={SOURCE} />;
}

Header actions

actions renders extra controls at the right end of the header, before the copy button. Use small icon buttons such as IconButton with size="sm".

import { useState } from 'react';
import { WrapText } from 'lucide-react';
import { CodeBlock, IconButton } from 'jarvis-react-ui';

const SOURCE = `const status = await fetch('/api/reactor/status').then((res) => res.json()); // a deliberately long line`;

export default function WithActions() {
    const [wrap, setWrap] = useState(false);

    return (
        <CodeBlock
            className={wrap ? '[&_pre]:whitespace-pre-wrap' : undefined}
            title="status.ts"
            language="ts"
            code={SOURCE}
            actions={
                <IconButton
                    icon={WrapText}
                    label={wrap ? 'Disable line wrap' : 'Enable line wrap'}
                    size="sm"
                    aria-pressed={wrap}
                    onClick={() => setWrap((w) => !w)}
                />
            }
        />
    );
}

Not copyable

Set copyable={false} to hide the copy button, e.g. for logs or output that nobody should paste. Without title, language, actions and the copy button, the header is not rendered at all.

import { CodeBlock } from 'jarvis-react-ui';

export default function NotCopyable() {
    return (
        <CodeBlock
            language="log"
            copyable={false}
            code={
                '[12:04:31] link established\n[12:04:32] handshake ok\n[12:04:33] streaming telemetry'
            }
        />
    );
}

Copy feedback

onCopy is called with the code after it reached the clipboard. Combine it with useToast to confirm the copy; reusing a toast id keeps repeated copies from stacking.

import { CodeBlock, useToast } from 'jarvis-react-ui';

export default function CopyToast() {
    const { toast } = useToast();

    return (
        <CodeBlock
            className="w-full"
            code="npm i jarvis-react-ui"
            language="bash"
            onCopy={() => toast({ id: 'copied', variant: 'success', title: 'Copied' })}
        />
    );
}

Syntax highlighting

CodeBlock does not ship a highlighter. To show colored code, highlight it yourself (ideally at build time, e.g. with shiki) and pass the resulting markup as html. It is injected into the <code> element, while code is still used for the copy button. Every code sample on this site works that way: the demo sources are highlighted by shiki during the build and handed to CodeBlock together with the raw source.

import { CodeBlock } from 'jarvis-react-ui';

const CODE = "import { Button } from 'jarvis-react-ui';";

// Trusted markup generated at build time (e.g. by shiki), never user input.
const HTML =
    '<span class="text-accent-bright">import</span> { Button } ' +
    '<span class="text-accent-bright">from</span> ' +
    '<span class="text-success">\'jarvis-react-ui\'</span>;';

export default function Highlighted() {
    return <CodeBlock title="App.tsx" language="tsx" code={CODE} html={HTML} />;
}

Warning: Trusted markup only

html is injected with dangerouslySetInnerHTML and is not sanitized. Only pass markup that you generated yourself from trusted sources. Never pass user input, URL parameters or API responses, because that opens the door to cross-site scripting (XSS).

Accessibility

  • The code is rendered in a native <pre><code>, which scrolls horizontally for long lines and keeps whitespace intact.
  • The copy button is an IconButton labelled "Copy code"; after a successful copy its label and tooltip switch to "Copied" for 1.5 seconds.
  • Copying uses the async Clipboard API, which browsers only allow in secure contexts (HTTPS or localhost). Where it is unavailable the button does nothing.

API

Prop Type Default Description
code (required) string Raw source code. Copied to the clipboard and rendered as plain text when html is absent.
actions ReactNode Content rendered at the right end of the header, next to the copy button.
className string Additional class names for the outer frame (wraps the header and the <pre>).
copyable boolean true Shows the copy-to-clipboard button.
html string Pre-highlighted markup for the inside of the <code> element, e.g. produced by shiki at build time. It is injected as HTML, so it must come from a trusted source, never from user input.
language string Language label shown in the header, e.g. tsx.
onCopy ((code: string) => void) Called with the code after it was copied to the clipboard, e.g. to show a toast. Not called when copying fails or the clipboard API is unavailable.
title ReactNode Title shown in the header, e.g. a file name.