Redpanda UIRedpanda UI

Code Block (Dynamic)

A codeblock that also highlights code. Based on Shiki 式 syntax highlighter

Made by malinskibeniamin

Installation

Loading component...

Usage

The Dynamic Code Block component provides server-side syntax highlighting using Shiki, with better performance and more accurate highlighting than client-side solutions:

import { 
  CodeBlock, 
  Pre, 
  DynamicCodeBlock 
} from '@/components/redpanda-ui/code-block-dynamic';

// Basic usage with automatic syntax highlighting
const sampleCode = `function greetUser(name: string): string {
  return \`Hello, \${name}! Welcome to Redpanda UI.\`;
}`;

export function Example() {
  return (
    <DynamicCodeBlock
      lang="typescript"
      code={sampleCode}
      options={{
        title: "greet.ts",
        icon: "📄",
        allowCopy: true,
        theme: { light: "github-light", dark: "github-dark" }
      }}
    />
  );
}

// Advanced usage with custom theming and line numbers
export function AdvancedExample() {
  return (
    <DynamicCodeBlock
      lang="typescript"
      code={sampleCode}
      options={{
        title: "greet.ts",
        icon: "📄",
        allowCopy: true,
        keepBackground: true,
        'data-line-numbers': true,
        'data-line-numbers-start': 1,
        themes: {
          light: "catppuccin-latte",
          dark: "catppuccin-mocha"
        },
        components: {
          // Custom component overrides
          pre: (props) => <Pre className="custom-pre" {...props} />
        }
      }}
    />
  );
}

// Manual CodeBlock usage for custom highlighting
export function ManualExample() {
  return (
    <CodeBlock 
      title="config.json" 
      icon="⚙️"
      allowCopy={true}
      keepBackground={false}
      data-line-numbers={true}
    >
      <Pre>
        <code className="language-json">
          {JSON.stringify({ theme: "dark", fontSize: 14 }, null, 2)}
        </code>
      </Pre>
    </CodeBlock>
  );
}

Synchronous highlighting (SyncCodeBlock)

DynamicCodeBlock tokenizes in a client effect via useShiki, so it renders a plain-text skeleton first and then swaps to highlighted markup — a brief flash that is especially visible on dark backgrounds. SyncCodeBlock avoids this by highlighting with a pre-bundled Shiki core highlighter (JS regex engine + statically imported grammars). Highlighting runs during render, so there is no loading skeleton and no highlight flash:

import { SyncCodeBlock } from '@/components/code-block-dynamic';

// Flash-free dark terminal: keepBackground keeps the theme's own background
// instead of the registry's bg-card, and both theme slots default to github-dark.
export function Terminal() {
  return <SyncCodeBlock code="rpk topic create my-topic" lang="bash" keepBackground />;
}

// It accepts the same chrome props as CodeBlock (title, icon, allowCopy, ...).
export function ConfigSnippet() {
  return (
    <SyncCodeBlock
      lang="yaml"
      code={'redpanda:\n  developer_mode: true'}
      title="redpanda.yaml"
      keepBackground
    />
  );
}

The trade-off is that the supported languages are fixed at build timebash, go, java, javascript, json, python, sql, tsx, typescript, and yaml — and ship in the bundle of any module that imports SyncCodeBlock. An unsupported lang falls back to plain (unhighlighted) text rather than throwing. The grammar imports are side-effect-free, so consumers that only use DynamicCodeBlock tree-shake them away.

  • Use SyncCodeBlock when: you render a small, known set of languages (terminals, config/SQL snippets) and want zero flash — ideal for dark themes.
  • Use DynamicCodeBlock when: you need arbitrary or à-la-carte languages, or line numbers and the full options surface.

When to use

Use this decision tree to determine when to use the Dynamic Code Block component over the regular Code Block:

Use Cases

  • Documentation sites: Technical documentation with accurate syntax highlighting
  • Code tutorials: Step-by-step programming guides with proper code display
  • API references: Code examples with language-specific highlighting
  • Blog posts: Technical articles with multiple code examples
  • Code showcases: Portfolio or demonstration code with professional presentation

Dynamic Code Block vs Regular Code Block

  • Use Dynamic Code Block when: You need server-side syntax highlighting, accurate language support, custom themes, or better performance with many code blocks
  • Use regular Code Block when: Client-side highlighting is sufficient, you have simple highlighting needs, or you're not using SSR
  • Use inline <code> when: Short code snippets within text content
  • Use Code Editor when: Users need to edit or interact with the code

Anatomy

The Dynamic Code Block component extends the regular Code Block with Shiki-powered syntax highlighting:

Dynamic Code Block Architecture:
┌─────────────────────────────────────────────────┐
│ DynamicCodeBlock (Wrapper Component)            │
│ ┌─────────────────────────────────────────────┐ │
│ │ useShiki Hook                               │ │
│ │ - Server-side syntax highlighting           │ │
│ │ - Theme management (light/dark)             │ │
│ │ - Language detection and parsing            │ │
│ │ - Component transformation                  │ │
│ └─────────────────────────────────────────────┘ │
│ ┌─────────────────────────────────────────────┐ │
│ │ Loading Fallback                            │ │
│ │ - Plain text display during SSR            │ │
│ │ - Line-by-line structure preserved         │ │
│ │ - Prevents layout shift                     │ │
│ └─────────────────────────────────────────────┘ │
│ ┌─────────────────────────────────────────────┐ │
│ │ CodeBlock (Enhanced Container)              │ │
│ │ ┌─────────────────────────────────────────┐ │ │
│ │ │ Header (with enhanced styling)          │ │ │
│ │ │ [Icon] Title Text [CopyButton]          │ │ │
│ │ │ - keepBackground option                 │ │ │
│ │ │ - Custom icon support                   │ │ │
│ │ └─────────────────────────────────────────┘ │ │
│ │ ┌─────────────────────────────────────────┐ │ │
│ │ │ Viewport (Scroll Container)             │ │ │
│ │ │ ┌─────────────────────────────────────┐ │ │ │
│ │ │ │ Pre (Syntax Highlighted)            │ │ │ │
│ │ │ │ ┌─────────────────────────────────┐ │ │ │ │
│ │ │ │ │ Line Elements                   │ │ │ │ │
│ │ │ │ │ - span.line containers          │ │ │ │ │
│ │ │ │ │ - Token-based highlighting      │ │ │ │ │  
│ │ │ │ │ - Line number support           │ │ │ │ │
│ │ │ │ │ - Counter-based numbering       │ │ │ │ │
│ │ │ │ └─────────────────────────────────┘ │ │ │ │
│ │ │ └─────────────────────────────────────┘ │ │ │
│ │ └─────────────────────────────────────────┘ │ │
│ └─────────────────────────────────────────────┘ │
│ ┌─────────────────────────────────────────────┐ │
│ │ CopyButton (Enhanced)                       │ │
│ │ - Animated check/copy icons                 │ │
│ │ - Smart text extraction                     │ │
│ │ - Hover state management                    │ │
│ │ - Accessibility features                    │ │
│ └─────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────┘

Shiki Integration Flow:
┌─────────────────────────────────────┐
│ Code String + Language              │
│ ↓                                   │
│ Shiki Highlighter                   │
│ - Tokenizes syntax                  │
│ - Applies theme colors              │
│ - Generates HAST tree               │
│ ↓                                   │
│ HAST to JSX Runtime                 │
│ - Converts to React elements        │
│ - Preserves syntax structure        │ 
│ - Applies custom components         │
│ ↓                                   │
│ Rendered Highlighted Code           │
└─────────────────────────────────────┘

Component Composition

  • DynamicCodeBlock: Main wrapper orchestrating syntax highlighting
  • useShiki Hook: Custom hook managing Shiki highlighting and SSR
  • CodeBlock: Enhanced container with dynamic theme support
  • Pre: Structured preformatted text element with line support
  • CopyButton: Advanced copy functionality with visual feedback
  • Theme Management: Automatic light/dark theme switching
  • Line Numbers: CSS counter-based line numbering system
  • Component Override: Customizable rendering via components prop
  • Performance: Server-side rendering with client hydration

Examples

Default

Loading component...

Credits

  • We use Fumadocs as inspiration for the dynamic code block component and style.

Recent changes

  • patchv1.2.0Pin shipped dependency floors to the version we develop against. Registry items now declare ranges like `^5.1.9` (the actual installed version) instead of collapsing to `^5.0.0`, so consumers start on the known-tested baseline while caret semantics still allow any compatible release within the same major.#133
  • minorv1.1.0Theme docs refresh, readability pass on semantic foregrounds, and consumer-facing Base UI regression fixes.#121
  • minorv1.0.0Post-Base-UI polish. Public API unchanged.#116
  • majorv1.0.0Migrate every Radix-based primitive to `@base-ui/react@^1.4.0` (Base UI).#114
  • minorv0.3.0Add theme-provider component to the registry with documentation and tests. Includes playground type improvements (export RegistryItem, remove as-const boilerplate) and docs site dark mode border color fix.#109
See full history →
Built by malinskibeniamin. The source code is available on GitHub.

On this page