コードブロック(Code Block)

シンタックスハイライト付きコードブロックの実装を4つのアプローチで比較。SSR対応・バンドルサイズ・ハイライト品質の違いを確認できます。

1. Shiki

Next.js App Routerに最適なサーバーサイドのシンタックスハイライター。 VS Code と同等のハイライト品質を持ち、クライアントバンドルに影響を与えない。

✓ SSRで動作✓ ゼロクライアントバンドル✓ VS Code相当の品質
tsx
import { useState } from 'react';

interface CounterProps {
  initialCount?: number;
}

export function Counter({ initialCount = 0 }: CounterProps) {
  const [count, setCount] = useState(initialCount);

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </div>
  );
}
特徴: サーバーサイドで実行するため、クライアントにJavaScriptを送らない。 テーマはVS Codeのテーマをそのまま使用でき、200以上のテーマと100以上の言語に対応。 Next.js App RouterのServer Componentとの相性が抜群。
tsx
// page.tsx(Server Component)
import { codeToHtml } from 'shiki';
import CodeBlockDisplay from './CodeBlockDisplay';

const code = `import { useState } from 'react';

export function Counter() {
  const [count, setCount] = useState(0);
  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </div>
  );
}`;

export default async function Page() {
  const html = await codeToHtml(code, {
    lang: 'tsx',
    theme: 'github-dark',
  });

  return <CodeBlockDisplay html={html} code={code} />;
}

// CodeBlockDisplay.tsx('use client' でコピーボタンを追加)
'use client';
import { useState } from 'react';

export default function CodeBlockDisplay({
  html,
  code,
}: {
  html: string;
  code: string;
}) {
  const [copied, setCopied] = useState(false);

  return (
    <div className="rounded-lg overflow-hidden">
      <div className="flex items-center justify-between bg-zinc-800 px-4 py-2">
        <span className="text-xs text-zinc-400">tsx</span>
        <button
          onClick={async () => {
            await navigator.clipboard.writeText(code);
            setCopied(true);
            setTimeout(() => setCopied(false), 2000);
          }}
          className="text-xs px-2 py-1 rounded border border-zinc-600 text-zinc-300"
        >
          {copied ? 'コピーしました ✓' : 'コピー'}
        </button>
      </div>
      <div dangerouslySetInnerHTML={{ __html: html }} />
    </div>
  );
}

🤖 AIプロンプトテンプレート

Next.js App Routerで、Shikiを使ったシンタックスハイライト付きコードブロックを実装してください。
- 使用ライブラリ: shiki の codeToHtml
- サーバーコンポーネントとして実装し、クライアントバンドルに影響を与えない
- テーマ: github-dark
- 言語: tsx
- コピーボタンを追加する(コピーボタン部分のみ 'use client')

⚠️ このプロンプトはあくまでたたき台です。AIの回答はモデルやバージョン、会話の文脈によって毎回異なります。意図通りに動かない場合は、条件を追記・修正してお使いください。

2. Prism.js

クライアントサイドで動作する老舗のシンタックスハイライターライブラリ。 豊富なテーマとプラグインエコシステムを持ち、幅広い言語に対応する。

✓ 豊富なテーマ✓ プラグイン対応✓ 実績豊富
tsx
import { useState } from 'react';

interface CounterProps {
  initialCount?: number;
}

export function Counter({ initialCount = 0 }: CounterProps) {
  const [count, setCount] = useState(initialCount);

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </div>
  );
}
特徴: クライアントサイドでuseEffectを使ってハイライトを適用する。 行番号表示・行のハイライトなど豊富なプラグインが揃っており、シンプルな静的サイトや React以外のプロジェクトにも使いやすい。
tsx
'use client';
import { useEffect, useRef } from 'react';
import Prism from 'prismjs';
import 'prismjs/components/prism-typescript';
import 'prismjs/components/prism-jsx';
import 'prismjs/components/prism-tsx';
import 'prismjs/themes/prism-tomorrow.css';

const code = `import { useState } from 'react';

interface CounterProps {
  initialCount?: number;
}

export function Counter({ initialCount = 0 }: CounterProps) {
  const [count, setCount] = useState(initialCount);
  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </div>
  );
}`;

export function CodeBlock() {
  const codeRef = useRef<HTMLElement>(null);

  useEffect(() => {
    if (codeRef.current) {
      Prism.highlightElement(codeRef.current);
    }
  }, []);

  return (
    <pre className="language-tsx">
      <code ref={codeRef} className="language-tsx">
        {code}
      </code>
    </pre>
  );
}

🤖 AIプロンプトテンプレート

Reactで、Prism.jsを使ったシンタックスハイライト付きコードブロックを実装してください。
- 使用ライブラリ: prismjs
- 'use client' コンポーネントとして実装
- テーマ: prism-tomorrow(またはダーク系テーマ)
- 言語: tsx
- useEffect でハイライトを適用する
- コピーボタンを追加する

⚠️ このプロンプトはあくまでたたき台です。AIの回答はモデルやバージョン、会話の文脈によって毎回異なります。意図通りに動かない場合は、条件を追記・修正してお使いください。

3. highlight.js

言語自動検出に対応した汎用のシンタックスハイライターライブラリ。 非Reactのプロジェクトにも使いやすく、ユーザーが任意のコードを貼り付けて表示するような用途に最適。

✓ 言語自動検出✓ 豊富な言語対応✓ フレームワーク非依存
tsx
import { useState } from 'react';

interface CounterProps {
  initialCount?: number;
}

export function Counter({ initialCount = 0 }: CounterProps) {
  const [count, setCount] = useState(initialCount);

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </div>
  );
}
特徴: 言語を指定しなくても自動で言語を検出してハイライトできる。 ユーザーが任意のコードを貼り付けて表示するCMS・ブログ・Wikiなどの用途に向いている。 コアとなる実装がシンプルで、React・Vue・Angularなどフレームワーク非依存で利用可能。
tsx
'use client';
import { useEffect, useRef } from 'react';
import hljs from 'highlight.js/lib/core';
import typescript from 'highlight.js/lib/languages/typescript';
import xml from 'highlight.js/lib/languages/xml';
import 'highlight.js/styles/github-dark.css';

hljs.registerLanguage('typescript', typescript);
hljs.registerLanguage('xml', xml);

const code = `import { useState } from 'react';

interface CounterProps {
  initialCount?: number;
}

export function Counter({ initialCount = 0 }: CounterProps) {
  const [count, setCount] = useState(initialCount);
  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </div>
  );
}`;

export function CodeBlock() {
  const codeRef = useRef<HTMLElement>(null);

  useEffect(() => {
    if (codeRef.current) {
      hljs.highlightElement(codeRef.current);
    }
  }, []);

  return (
    <pre>
      <code ref={codeRef} className="language-typescript">
        {code}
      </code>
    </pre>
  );
}

🤖 AIプロンプトテンプレート

Reactで、highlight.jsを使ったシンタックスハイライト付きコードブロックを実装してください。
- 使用ライブラリ: highlight.js
- 'use client' コンポーネントとして実装
- テーマ: github-dark
- 言語: typescript(自動検出も可)
- useEffect でハイライトを適用する
- コピーボタンを追加する

⚠️ このプロンプトはあくまでたたき台です。AIの回答はモデルやバージョン、会話の文脈によって毎回異なります。意図通りに動かない場合は、条件を追記・修正してお使いください。

4. プレーン HTML

追加ライブラリなしで実装するシンプルなコードブロック。<pre><code>とTailwind CSSのみを使用。

✓ 依存ゼロ✓ 最軽量✓ どんな環境でも動作
tsx
import { useState } from 'react';

interface CounterProps {
  initialCount?: number;
}

export function Counter({ initialCount = 0 }: CounterProps) {
  const [count, setCount] = useState(initialCount);

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </div>
  );
}
特徴: シンタックスハイライトは行わず、等幅フォントとダーク背景のみでコードを表示する。 コマンド例・ファイルパス・設定値など、ハイライト不要な短いコードブロックに十分。 追加依存ゼロのため、どんな環境でもそのまま使える。
tsx
import { useState } from 'react';

const code = `import { useState } from 'react';

interface CounterProps {
  initialCount?: number;
}

export function Counter({ initialCount = 0 }: CounterProps) {
  const [count, setCount] = useState(initialCount);
  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </div>
  );
}`;

export function PlainCodeBlock() {
  const [copied, setCopied] = useState(false);

  return (
    <div className="rounded-lg overflow-hidden border border-zinc-700">
      <div className="flex items-center justify-between bg-zinc-800 px-4 py-2">
        <span className="text-xs text-zinc-400 font-mono">tsx</span>
        <button
          onClick={async () => {
            await navigator.clipboard.writeText(code);
            setCopied(true);
            setTimeout(() => setCopied(false), 2000);
          }}
          className="text-xs px-2 py-1 rounded border border-zinc-600 text-zinc-300 hover:bg-zinc-700"
        >
          {copied ? 'コピーしました ✓' : 'コピー'}
        </button>
      </div>
      <pre className="bg-zinc-900 p-4 overflow-x-auto m-0">
        <code className="text-zinc-100 text-sm font-mono whitespace-pre">{code}</code>
      </pre>
    </div>
  );
}

🤖 AIプロンプトテンプレート

Reactで、ライブラリなしのシンタックスハイライト付きコードブロックを実装してください。
- 追加ライブラリなし、<pre><code> のみ使用
- Tailwind CSS でスタイリング(ダーク背景、等幅フォント)
- コピーボタンを追加する
- ハイライトは不要(モノクロで可)

⚠️ このプロンプトはあくまでたたき台です。AIの回答はモデルやバージョン、会話の文脈によって毎回異なります。意図通りに動かない場合は、条件を追記・修正してお使いください。

ライブラリ比較表

項目ShikiPrism.jshighlight.jsプレーン HTML
動作環境サーバー(SSR)クライアントクライアントどちらでも
バンドルサイズゼロゼロ
ハイライト品質VS Code相当良好良好なし
言語自動検出
テーマ数多(VS Codeテーマ対応)自前
Next.js との相性◎ App Router最適
導入の手軽さ最易

選択のポイント

  • Shiki — Next.js App Router との相性が最も良く、サーバーサイドでハイライト済みHTMLを生成するためクライアントのバンドルサイズに影響しない。VS Codeと同等のハイライト品質が必要な場合に最適。
  • Prism.js — クライアントサイドで動作する老舗ライブラリ。テーマが豊富でドキュメントも充実しており、React以外のプロジェクトにも使いやすい。
  • highlight.js — 言語自動検出が特徴。ユーザーが任意のコードを貼り付けて表示するような用途(言語が不定)に向いている。
  • プレーン HTML — 追加依存ゼロ。コマンド例やファイルパスなどハイライト不要な短いコードブロックに十分。