Skip to main content
Urbicon UI

CodeBlockexperimental

Read-only code display card with a copy button, an accessible copy status, and horizontal scroll kept inside the block. It renders raw text, so syntax highlighting comes from a consumer or the StreamingMarkdown renderer.

Playground

ts
type Source = { id: string; title: string; url?: string };

function cite(sources: Source[]): string {
  return sources.map((s, i) => `[${i + 1}] ${s.title}`).join('\n');
}
Variant Style variant
<CodeBlock lang="ts" {code} />

01 Examples

Multi-line code

Pass the code as a string. It renders as raw text with no built-in highlighting, and long lines scroll horizontally inside the block rather than the page.
ts
import { CodeBlock } from '@urbicon-ui/blocks';

export function greet(name: string): string {
  return `Hello, ${name} — this line is long enough to scroll inside the block.`;
}
<script lang="ts">
  import { CodeBlock } from '@urbicon-ui/blocks';

  // Rendered as raw text — CodeBlock never highlights on its own. Long lines
  // scroll horizontally inside the block, so the page never scrolls sideways.
  const code = `import { CodeBlock } from '@urbicon-ui/blocks';

export function greet(name: string): string {
  return \`Hello, \${name} — this line is long enough to scroll inside the block.\`;
}`;
</script>

<CodeBlock lang="ts" {code} />

Track copies with onCopy

onCopy fires only after the clipboard write succeeds, so it is a safe place to record an event like 'install command copied'.
bash
curl -fsSL https://ui.urbicon.de/install.sh | sh

Copied 0 times.

<script lang="ts">
  import { CodeBlock } from '@urbicon-ui/blocks';

  // onCopy fires only after the clipboard write succeeds — the perfect hook for
  // analytics ("install command copied") without polling the clipboard.
  let copies = $state(0);
  const code = 'curl -fsSL https://ui.urbicon.de/install.sh | sh';
</script>

<div class="w-full space-y-2">
  <CodeBlock lang="bash" {code} onCopy={() => (copies += 1)} />
  <p class="text-text-tertiary text-xs">
    Copied {copies} time{copies === 1 ? '' : 's'}.
  </p>
</div>

Extra header actions

The actions snippet renders custom controls in the header, just before the copy button: a 'Run' button, 'Open in editor', or a language switch.
sql
SELECT id, title FROM sources WHERE cited = true;
<script lang="ts">
  import { CodeBlock, Button } from '@urbicon-ui/blocks';

  // The `actions` snippet renders extra controls in the header, before the copy
  // button — e.g. "Run in playground", "Open in editor".
  const code = 'SELECT id, title FROM sources WHERE cited = true;';
</script>

<CodeBlock lang="sql" {code}>
  {#snippet actions()}
    <Button variant="ghost" size="sm">Run</Button>
  {/snippet}
</CodeBlock>

02 Accessibility

Copy button label

The copy button carries an aria-label that swaps from copyLabel ("Copy") to copiedLabel ("Copied") for two seconds after a successful copy, so its accessible name always matches what the user sees. A denied or failed clipboard write leaves the label unchanged, so a copy is confirmed only when it actually happened.

Status announcement

A visually hidden role="status" region announces "Copied" to screen readers. It ships in the DOM up front and only its text content changes, which assistive tech announces reliably.

Scrollable region

The code body is a focusable role="region" (tabindex="0") labelled by the language, so keyboard users can reach and scroll horizontally overflowing code (WCAG 2.1.1). Focus rings use focus-visible: for keyboard-only visibility.

03 API Reference

18 props
18 props 1 required
Prop
Type
Default
Description

04 Types

Local type definitions used by this component.

5 types
Name
Kind
Category
Used by
Description

05 Installation

Import

import { CodeBlock } from '@urbicon-ui/blocks';
import type { CodeBlockProps } from '@urbicon-ui/blocks';