CodeBlockCard

Stream, inspect, copy, and download one source-code snippet.

CodeBlockCard renders one display-ready source snippet with line numbers, plain-text copy/download, and Shiki syntax highlighting. It treats code as text: it never executes the snippet or writes it into the host project.

welcome.ts

ts

export const welcome = "Hello"
import { CodeBlockCard } from "@/components/fable-ui/code-block-card"

export function InstallCommand() {
  return (
    <CodeBlockCard
      language="ts"
      filename="welcome.ts"
      code={'export const welcome = "Hello"'}
    />
  )

Installation

pnpm dlx shadcn@latest add shobky/fable-ui/code-block-card

The registry item installs:

components/fable-ui/code-block-card/index.ts
components/fable-ui/code-block-card/code-block-card.tsx
hooks/use-copy-to-clipboard.ts
lib/fable-ui/tools/show-code-block-tool.ts
lib/fable-ui/manifests/show-code-block.md

It uses the installed shiki package plus shadcn alert, button, card, empty, and skeleton primitives, and shared Fable core.

Usage

import { CodeBlockCard } from "@/components/fable-ui/code-block-card"
 
export function InstallCommand() {
  return (
    <CodeBlockCard
      language="ts"
      filename="welcome.ts"
      code={'export const welcome = "Hello"'}
    />
  )
}

Use showLineNumbers={false} for a very small snippet. Copy and Download live in compact, accessible icon actions at the card’s logical inline end. Download uses the supplied filename when safe, or derives a file extension from the language.

Streaming highlighting

During streaming, the card first shows a plain-text fallback, then re-highlights the latest code with the existing shiki@3.23.0 API roughly every 150ms. Each scheduled timer is cancellable; in-flight Shiki work is guarded by its code key/request id, so an old asynchronous result is ignored rather than replacing newer HTML. The completed part triggers an exact immediate highlight flush.

Successful results use a bounded, recency-refreshed cache of at most 40 entries; the oldest successful highlight is evicted as new sources arrive.

If a language is unsupported or Shiki fails, the raw code remains visible with optional line numbers. This favors an honest readable fallback over stale or missing source. The card does not use @shikijs/stream.

Tool definition

The AI SDK tool name is show_code_block.

{
  language: string
  code: string
  filename?: string
  showLineNumbers?: boolean
}

Use it for one complete or streaming code snippet that benefits from inspection, copying, or download. Do not use it for shell execution, host file writes, secrets, a source tree, rich text, or a prose draft.

lib/fable-ui/tools/show-code-block-tool.ts
import { tool } from "ai"
import { z } from "zod"

import {
  CodeBlockCard,
  type CodeBlockCardProps,
} from "@/components/fable-ui/code-block-card"
import { defineFableComponent } from "@/lib/fable-ui/core/definitions"

export const showCodeBlockInputSchema = z.object({
  language: z.string().min(1),
  code: z.string(),
  filename: z.string().min(1).optional(),
  showLineNumbers: z.boolean().default(true),
})

export type ShowCodeBlockInput = z.infer<typeof showCodeBlockInputSchema>

function getPartialCodeBlockProps(input: unknown): CodeBlockCardProps {
  const partial =
    input && typeof input === "object" ? (input as Record<string, unknown>) : {}

  return {
    language: typeof partial.language === "string" ? partial.language : "text",
    code: typeof partial.code === "string" ? partial.code : "",
    filename:
      typeof partial.filename === "string" ? partial.filename : undefined,
    showLineNumbers:
      typeof partial.showLineNumbers === "boolean"
        ? partial.showLineNumbers
        : true,
    isStreaming: true,
  }
}

export function createShowCodeBlockTool() {
  return tool({
    description:
      "Show a complete code snippet for review, copying, or download. Include its programming language and raw source. Do not use for executable host commands, file writes, secret values, rich text, or prose drafts.",
    inputSchema: showCodeBlockInputSchema,
    execute: async (input) => input,
  })
}

export const showCodeBlock = defineFableComponent({
  name: "show_code_block",
  schema: showCodeBlockInputSchema,
  tool: createShowCodeBlockTool(),
  renderer: {
    Component: CodeBlockCard,
    loadingProps: { language: "text", code: "", isLoading: true },
    streamingProps: getPartialCodeBlockProps,
    emptyProps: { language: "text", code: "" },
    errorProps: (description, part) => ({
      ...getPartialCodeBlockProps(part?.input),
      isStreaming: false,
      error: { title: "Code block unavailable", description },
    }),
    toProps: (data: ShowCodeBlockInput) => data,
  },
})

States

StateBehavior
ReadyRenders the final Shiki highlight or raw fallback, with Copy and Download enabled for source.
LoadingShows a preparing status and skeleton.
StreamingKeeps the source selectable, begins plain, and coalesces live Shiki updates about every 150ms.
EmptyExplains that no source is available.
ErrorShows the error and retains any available code as raw, copyable, downloadable text.
DisabledMarks the snippet read-only; code remains copyable and downloadable because no execution or mutation is involved.

Direction and accessibility

Metadata inherits the host direction while the source surface is explicitly LTR, including inside RTL documents. Icon actions have accessible names and tooltips, loading status is announced, and line numbers are visual metadata rather than a replacement for code text.

Manifest and caveats

lib/fable-ui/manifests/show-code-block.md
---
tool: show_code_block
type: registry:component
---

# show_code_block

Use `show_code_block` for a display-ready code snippet that benefits from syntax highlighting, copying, or download. During streaming it can show a readable raw fallback while the current code is highlighted.

Provide raw `code` and a short `language` identifier such as `ts`, `tsx`, `python`, or `sql`. Optionally provide `filename` and set `showLineNumbers: false` for very small snippets.

Avoid it for commands that should execute automatically, file writes, secrets, long prose, rich text, or partial host-owned source trees. The card renders source as text and never executes it.

Syntax highlighting is presentation only. It cannot prove the code compiles, is safe to execute, or has access to a host runtime.