Prism.js でシンタックスハイライト

シンタックスハイライト用のプラグイン Prism.js の使い方についての覚書です。

作成日:2023年12月28日

関連ページ:Highlight.js でシンタックスハイライト

Prism.js

Prism.js はシンタックスハイライト用の軽量でシンプル且つ多機能なプラグインです。

この時点でのバージョンは v1.29.0 で最終更新は 8/23/2022 となっていて1年以上更新されていません。

Roadmap for Prism v2 のページによると、現在 Prism v2 の準備中とありますが、現時点ではいつ v2 がリリースされるかは未定のようです。

Prism.js 以外の定評のあるシンタックスハイライターに Highlight.js がありますが、こちらは継続的に更新されています(Highlight.js でシンタックスハイライト)。

Prism.js を使用するには、サイトから JavaScript と CSS のファイルをダウンロードするか、CDN で読み込む、または npm でインストールします。

Prism.js でシンタックスハイライトするとどのように表示されるかは、トップページの右側のテーマ(Theme)の名前をクリックしてサンプル部分(Examples)で確認することができます。

Examples には Prism.js のソースコードが表示されています。

CDN で試してみる

手っ取り早く Prism.js を試すには、以下のようにテーマの CSS と JavaScritp(コアファイルとオートローダー)を CDN 経由で読み込みます(オートローダーは必要な言語ファイルをロードします)。

そしてシンタックスハイライトするコードブロックを <pre><code></code></pre> で囲み、code タグに language-言語名 という形式のクラスを指定します。

シンタックスハイライトするコード部分の HTML 特殊文字はエスケープします。

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <!-- Prism.js のテーマ CSS ファイル -->
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/themes/prism.min.css">
  <title>Prism.js Sample</title>
</head>
<body>
  <!-- Prism.js で JavaScript コードをシンタックスハイライト -->
  <pre><code class="language-javascript">Vue.createApp({
  data() {
    return {
      rand: 0  // 初期値
    }
  },
  methods: {
    onclick() {
      this.rand = Math.random();
    }
  }
}).mount(&#39;#app&#39;);</code></pre>

  <!-- Prism.js のコアファイル -->
  <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/prism-core.min.js"></script>
  <!-- Prism.js のオートローダー-->
  <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/autoloader/prism-autoloader.min.js"></script>
</body>
</html>

上記は以下のように表示されます。

テーマの CSS のファイル名の部分 prism.min.css は以下を指定することができ、異なるスタイルを確認できます。

  • prism-coy.min.css
  • prism-dark.min.css
  • prism-funky.min.css
  • prism-okaidia.min.css
  • prism-solarizedlight.min.css
  • prism-tomorrow.min.css
  • prism-twilight.min.css

必要に応じて、プラグインも CDN 経由で読み込むことができますが、CSS と JavaScript の両方の読み込みが必要です。

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/themes/prism-tomorrow.min.css">
  <!-- 行番号表示用の CSS -->
  <link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/line-numbers/prism-line-numbers.min.css">
  <title>Prism.js Sample</title>
</head>
<body>

  <pre class="line-numbers"><code class="lang-js">function add(x,y) {
  return x + y;
}</code></pre>

  <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/prism-core.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/autoloader/prism-autoloader.min.js"></script>
  <!-- 行番号表示用のプラグイン -->
  <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/line-numbers/prism-line-numbers.min.js"></script>
</body>
</html>

プラグインを複数使う場合など、CDN を利用すると読み込むファイルが増えてしまいますが、ダウンロードして使用する場合は、1つの JavaScript と1つの CSS にまとめることができます。

ダウンロード

以下のダウンロードページから JavaScript と CSS ファイルをダウンロードすることができます。

https://prismjs.com/download.html

ダウンロードページでは、使用する Theme(スタイル)や言語、プラグインを選択することで必要な機能だけを含むファイルをダウンロードすることができます。

以下は選択するそれぞれの項目の詳細です。

Compression level

ダウンロードページの一番上の Compression level では Development version または Minified version を選択します。

本番環境用に使用する場合は、圧縮されてファイルサイズが小さい Minified version を選択します。

ソースコードを確認するなど開発環境用として使用する場合は Development version を選択します。

Themes(テーマ)

テーマの選択では、以下の8個のテーマが用意されており好みのテーマを選択して、そのスタイル(CSS)をダウンロードすることができます。

  • Default
  • Dark
  • Funky
  • Okaidia
  • Twilight
  • Coy
  • Solarized Light
  • Tomorrow Night

Coy のテーマではフレックスボックスとフロートを組み合わせると、影と背景がコードの周囲に正しく回り込まない可能性があります(対応策)。

Languages(言語)

言語の選択では、非常にたくさんの言語がありますが、使用する言語だけを選択することでファイルサイズを抑えることができます。

また、言語によっては依存関係があります。

例えば、React TSX を選択すると、自動的に React JSX と TypeScript も選択されます。そのため、チェックを入れてないのに自動的にチェックがに入っている言語は必要なのでそのままにしておきます。

Plugins(プラグイン)

prism.js ではダウンロードする際に、必要なプラグインを選択することができます。

例えば、コードに行番号を表示するには Line Numbers プラグインを、指定した行をハイライト表示するには Line Highlight プラグインを選択してダウンロードします。

また、依存関係のあるプラグインもあり、例えば、Show Language や Copy to Clipboard Button プラグインを選択すると、Toolbar プラグインも自動的に選択されます。

各プラグインの概要は Plugins に記載されています。また、プラグイン名をクリックすると、そのプラグインの詳細及び使い方のページ(例 Line Numbers)が表示されます。

このページのプラグインを使うでも代表的なプラグインの使い方を解説しています。

JS と CSS のダウンロード

Compression level(ファイル形式)、Themes(テーマ)、Languages(言語)、Plugins(プラグイン)を選択したら、一番下の DOWNLOAD JS 及び DOWNLOAD CSS をクリックして、JavaScript と CSS のファイルをそれぞれダウンロードします。

Total filesize にはダウンロードするファイルのサイズ(JS と CSS の合計)が表示されます。

上記は Minified version を選択し、Themes で Tomorrow Night を選択した場合の例です。

Development version を選択した場合、以下のようにこの部分にミニファイされていない状態でコードが表示されます(このままダウンロードするとファイルサイズは大きくなります)。

複数のテーマを選択できないので、異なるテーマを試したい場合はそれぞれダウンロードします。

選択した項目

ダウンロードしたファイルの先頭には、以下のように選択したテーマや言語、プラグインがコメントとして記述されているので、後で何を選択したのかを確認することができます。

/* PrismJS 1.29.0
https://prismjs.com/download.html#themes=prism-tomorrow&languages=markup+css+clike+javascript+apacheconf+bash+csv+git+http+json+markup-templating+perl+php+python+jsx+tsx+sass+scss+sql+typescript+typoscript&plugins=line-highlight+line-numbers+show-language+highlight-keywords+keep-markup+command-line+toolbar+copy-to-clipboard+match-braces+treeview */ 

ファイルの読み込み

Prism.js を使用するページで、ダウンロードした JavaScript(prism.js)と CSS(prism.css)を読み込みます。CSS は <head> 内で、JavaScritp は body の閉じタグ </body> の直前あたりで読み込みます。

以下は prism.css を css フォルダに、prism.js を js フォルダに保存した場合の例です。

<!DOCTYPE html>
<html>
<head>
  ...
  <!-- head 内で CSS を読み込む -->
  <link href="css/prism.css" rel="stylesheet" />
</head>
<body>
  ...
  <!-- body の閉じタグの直前あたりで JavaScript を読み込む -->
  <script src="js/prism.js"></script>
</body>
</html>

基本的な使い方

シンタックスハイライト表示させたいコードを <code></code> タグで囲みます。

そして、<code> タグに class="language-言語名" または短縮形の class="lang-言語名" の形式で表示言語を指定したクラス(ここでは言語クラスと呼びます)を設定します。

例えば、HTML コードの表示であれば language-html または lang-html という言語クラスを<code> タグに指定します。

Supported languages のページに言語のリストが掲載されているので、それぞれの言語の指定する文字列を確認できます。JavaScript の場合、言語名の部分は javascript または js と指定できるなど、短縮形が用意されているものもあります。

以下は CSS のコードをシンタックスハイライト表示する例です(language-css クラスを指定)。

<code class="language-css">#foo {color: red;} </code>

上記を記述すると、例えば以下のように表示されます(テーマが Tomorrow Night の場合)。

#foo {color: red;}

複数行のコード(コードブロック)は pre タグで囲む

複数行のコードをシンタックスハイライト表示する場合は全体を <pre> タグで囲みます。

<pre><code class="language-css">#foo {
  color: red;
}</code></pre>

上記を記述すると以下のように表示されます。

#foo {
  color: red;
}

HTML 特殊文字はエスケープ

シンタックスハイライトするコード部分の HTML 特殊文字(< >& ' ")はそれぞれ &lt; &gt; &amp; &#39; &quot; にエスケープします。関連ページ:HTML特殊文字変換

例えば、以下のように記述すると(class="lang-js" は class="language-javascript" の短縮形)、

<pre><code class="lang-js">fetch(&#39;file.txt&#39;)
.then(response =&gt; {
  console.log(response);
});</code></pre>

以下のようにシンタックスハイライトされて表示されます。

fetch('file.txt')
.then(response => {
  console.log(response);
});

言語クラスは継承される

複数の code 要素が同じ言語を持つ場合、それらの共通の祖先に language-xxxx クラスを追加できます。

この方法を使うと、body 要素または html 要素に language-xxxx クラスを追加することで、ドキュメント全体のデフォルト言語を定義することもできます。

例えば、<body class="language-html"> とすると、そのページの全ての <code> タグ(インラインも)は何もクラスを指定しなくても HTML としてシンタックスハイライト表示されます。

異なる言語でシンタックスハイライトするには、その部分の <code> タグに language-xxxx クラスを指定します。

言語クラスを継承する code 要素のシンタックスハイライトを止めるには、その <code> タグに language-none クラスを指定します。

行の折り返し

デフォルトでは pre 要素内では自動的に行を折り返さない設定となっているので、自動的に行を折り返すようにするには、例えば以下のような white-space を使った CSS でスタイルを上書きします。

pre[class*='language-'],
code[class*='language-'] {
  white-space: pre-wrap;
}

以下はフォルトでは自動的に行を折り返し、pre や code 要素に nowrap クラスを指定すると行を折り返さないようにする例です(場合によっては pre と code の両方に .nowrap を指定する必要があります)。

pre[class*='language-'],
code[class*='language-'] {
  white-space: pre-wrap;
}

pre[class*='language-'].nowrap,
code[class*='language-'].nowrap {
  white-space: pre;
}

Prism.js により出力されるコード

Prism.js を読み込んだページで <code> タグに class="language-言語名" を指定した部分は Prism.js の JavaScript によりシンタックスハイライト用の HTML に変換されて出力されます。

例えば、以下を Prism.js を読み込んだページに記述すると、

<pre><code class="lang-js">function add(x,y) {
  return x + y;
}</code></pre>

以下のスクリーンショットのように表示され、実際の出力は開発ツールで確認できます。

ブラウザの開発ツールの「要素タブ」で見ると、<pre><code> タグの両方に language-js クラスが付与され、文字列が機能別に token クラスを付与された <span> 要素に分割されているのが確認できます。

また、<span> 要素には、token クラスの他に解析された文字列により keywordfunction などのクラスが指定されています。

例えば、上記の add の部分は <span class="token function">add</span> のように .token.function というクラスが付与されているので、例えば以下のように指定することでその部分のスタイルを設定することもできます。

.language-js .token.function {
  color: aquamarine;
}

例えば、以下のように表示されます。

function add(x,y) {
  return x + y;
}

但し、この場合、全ての .language-js .token.function の要素にスタイルが適用されるので、必要に応じてその親要素や pre 要素にクラスを指定するなどして限定することができます。

また、テーマの開発用(Development version)のスタイルをダウンロードして、CSS を確認して必要な部分を独自のスタイルシートで上書きするなどして比較的簡単にカスタマイズすることができます。

プラグインを使う

プラグインを利用するには、必要に応じてマークアップ(pre 要素や code 要素)にクラスやカスタムデータ属性を追加してカスタマイズすることができます。

Line Numbers(行番号表示)

Line Numbers プラグインを使うと、行番号を表示することができます。

行番号を表示するには、表示するコードブロックの <pre> 要素またはその親要素に line-numbers クラスを指定します(line-numbers クラスは継承されます)。

<pre class="line-numbers"><code class="lang-js">Vue.createApp({
  data() {
    return {
      rand: 0
    }
  },
  methods: {
    onclick() {
      this.rand = Math.random();
    }
  }
}).mount(&#39;#app&#39;);</code></pre>

以下のように行番号が表示されます。

Vue.createApp({
  data() {
    return {
      rand: 0
    }
  },
  methods: {
    onclick() {
      this.rand = Math.random();
    }
  }
}).mount('#app');

data-start

data-start 属性(カスタムデータ属性)を追加して開始する行番号を指定することができます。

以下は10行目から行番号を開始する例です。

<pre class="line-numbers" data-start="10"><code class="lang-js">Vue.createApp({
  data() {
    return {
      rand: 0
    }
  },
  methods: {
    onclick() {
      this.rand = Math.random();
    }
  }
}).mount(&#39;#app&#39;);</code></pre>

以下のように10行目から行番号が開始されます。

Vue.createApp({
  data() {
    return {
      rand: 0
    }
  },
  methods: {
    onclick() {
      this.rand = Math.random();
    }
  }
}).mount('#app');

全てのコードブロックで行番号を表示

そのページの全てのコードブロックで行番号を表示するには <body> 要素や最上位のコンテナ要素に line-numbers クラスを指定することができます。その場合、行番号を表示したくないコードブロックでは <pre> 要素に no-line-numbers クラスを指定します。

また、全てのページで読み込んでいる JavaScript に以下を記述すると、全てのページの全てのコードブロックで行番号を表示します。

document.body.classList.add('line-numbers');

以下は <body> 要素に no-line-numbers クラスが指定されていなければ、line-numbers クラスを追加する例です。

const bodyClassList = document.body.classList;
if(!bodyClassList.contains('no-line-numbers')) {
  bodyClassList.add('line-numbers');
}

Line Highlight(行単位のハイライト)

Line Highlight プラグインを使うと、行単位でハイライト表示することができます。

行単位でハイライトさせるには <pre> 要素に data-line 属性を追加して対象の行を指定します。

以下は2行目をハイライトさせる例です。

<pre data-line="2"><code class="lang-css">.box {
  aspect-ratio: 16/9;
  width: 100%;
  background-color: #7aac81;
  color: #ddd;
  padding: 1rem;
}</code></pre>

例えば以下のように表示されます(以下の場合、デフォルトのスタイルを変更してあります)。

.box {
  aspect-ratio: 16/9;
  width: 100%;
  background-color: #7aac81;
  color: #ddd;
  padding: 1rem;
}

data-line="2,5" とすると2行目と5行目を、data-line="2-5" とすると2行目から5行目を、data-line="1, 3-5" とすると1行目と3行目から5行目をハイライトします。

data-line-offset

data-line-offset 属性を使ってオフセット(開始位置オフセット)を設定できます。以下は data-line-offset="20" で開始行を20として22-25行目をハイライトさせる例です。

<pre data-line="22-25" data-line-offset="20"><code class="lang-css">.box {
  aspect-ratio: 16/9;
  width: 100%;
  background-color: #7aac81;
  color: #ddd;
  padding: 1rem;
}</code></pre>

以下のように表示されます。

.box {
  aspect-ratio: 16/9;
  width: 100%;
  background-color: #7aac81;
  color: #ddd;
  padding: 1rem;
}

Line Numbers と併用

行番号表示プラグイン Line Numbers と一緒に使用することもできます。

              <pre class="line-numbers" data-line="3-5"><code class="lang-css">.box {
  aspect-ratio: 16/9;
  width: 100%;
  background-color: #7aac81;
  color: #ddd;
  padding: 1rem;
}</code></pre>
.box {
  aspect-ratio: 16/9;
  width: 100%;
  background-color: #7aac81;
  color: #ddd;
  padding: 1rem;
}

ハイライトのスタイル

Line Highlight のスタイルは以下のように .line-highlight に設定されています。

.line-highlight {
  position: absolute;
  left: 0;
  right: 0;
  padding: inherit 0;
  margin-top: 1em; /* Same as .prism’s padding-top */
  background: hsla(24, 20%, 50%,.08);
  background: linear-gradient(to right, hsla(24, 20%, 50%,.1) 70%, hsla(24, 20%, 50%,0));
  pointer-events: none;
  line-height: inherit;
  white-space: pre;
}

行番号部分のスタイルは .line-highlight:before(開始行) と .line-highlight[data-end]:after(終了行)に以下のように設定されています。

.line-highlight:before,
.line-highlight[data-end]:after {
  content: attr(data-start);
  position: absolute;
  top: .4em;
  left: .6em;
  min-width: 1em;
  padding: 0 .5em;
  background-color: hsla(24, 20%, 50%,.4);
  color: hsl(24, 20%, 95%);
  font: bold 65%/1.5 sans-serif;
  text-align: center;
  vertical-align: .3em;
  border-radius: 999px;
  text-shadow: none;
  box-shadow: 0 1px white;
}

url hash

url hash を使って、リンク先の特定の行をハイライトすることができます。

hash は #{element-id}.{lines} の形式で指定します。#{element-id} は pre 要素に指定した id 属性の値、{lines} は行番号の指定です。

例えば、以下のように pre 要素に id 属性 highlight が指定されている場合、

<pre id="highlight"><code class="lang-css">.box {
  aspect-ratio: 16/9;
  width: 100%;
  background-color: #7aac81;
  color: #ddd;
  padding: 1rem;
}</code></pre>

ページの URL#highlight.3-5 という hash を付けたリンクでアクセスすると、3〜5行目がハイライト表示されます(リンクをクリックすると別タブでこのページが開き以下のコードの3〜5行目がハイライトされて表示されます)。

.box {
  aspect-ratio: 16/9;
  width: 100%;
  background-color: #7aac81;
  color: #ddd;
  padding: 1rem;
}

Highlight Keywords

Highlight Keywords プラグインはコードの中の if や return などのキーワードに keyword-キーワード名 のような名前のクラスを追加するので、そのクラスを使ってキーワード固有のスタイルを適用できます。

例えば、キーワード if には keyword-if クラスが追加されるので、以下のようにスタイルを指定することができます。

.sample .token.keyword.keyword-if { color: pink; }
<div class="sample">
  <pre><code class="lang-js">if(foo) x = 7;</code></pre>
</div>

上記の場合、以下のように if が pink で表示されます。

if(foo) x = 7;

上記は以下のように変換されて出力されます。Highlight Keywords プラグインによりキーワードに keyword-if クラスが追加されています。

<div class="sample">
  <pre class="language-js" tabindex="0">
    <code class="language-js">
      <span class="token keyword keyword-if">if</span>
      <span class="token punctuation">(</span>
      foo
      <span class="token punctuation">)</span>
      x
      <span class="token operator">=</span>
      <span class="token number">7</span>
      <span class="token punctuation">;</span>
    </code>
  </pre>
</div>

Keep Markup

デフォルトでは language-xxxx クラスを指定した <code> 要素内に記述したマークアップはシンタックスハイライト表示する際に削除されますが、Keep Markup プラグインを入れるとマークアップを残すことができます。

このプラグインの機能を無効にするには、そのコードブロックに no-keep-markup クラスを指定します。ページ全てで無効にするには body 要素に no-keep-markup クラスを指定します。

以下はシンタックスハイライトするコードブロック内に <mark> 要素(4行目)を追加する例です。

<pre class="foo"><code class="lang-js">Vue.createApp({
  data() {
    return {
      rand: 0  // <mark>初期値</mark>
    }
  }
}).mount(&#39;#app&#39;);</code></pre>

以下のようなスタイルを設定すると、

.foo .language-js mark {
  color: #b94f4f;
  background-color: #f8e1f1;
}

以下のように<mark> 要素にスタイルが適用されて表示されます。

Vue.createApp({
  data() {
    return {
      rand: 0  // 初期値
    }
  }
}).mount('#app');

以下は class="foo" を指定した <span> 要素を追加する例です。

<pre class="foo"><code class="lang-js">Vue.createApp({
  data() {
    return {
      <span class="yellow">rand: 0  // 初期値</span>
    }
  }
}).mount(&#39;#app&#39;);</code></pre>

この例では追加した <span> 要素の配下の全ての <span> 要素の文字色を設定しています。

.foo .language-js span.yellow span {
  color: yellow;
}

<span class="yellow"> を追加した部分はシンタックスハイライトの際に以下のように変換されます。

<span class="yellow">
  <span class="token literal-property property">rand</span>
  <span class="token operator">:</span>
  <span class="token number">0</span>
  <span class="token comment">// 初期値</span>
</span>

<span class="yellow"> の配下の span 要素全てにスタイルが適用されて以下のように表示されます。

              Vue.createApp({
  data() {
    return {
      rand: 0  // 初期値
    }
  }
}).mount('#app');

Normalize Whitespace

デフォルトでは、Normalize Whitespace プラグインはすべてのコードブロックの先頭と末尾の空白文字(whitespace)、及び各行の余分なインデントと末尾の空白をすべて削除します。

no-whitespace-normalization クラスを <pre> タグまたは <code> タグのいずれかに追加することで、特定のコードブロックに対してプラグインを無効にできます。

<body> タグに no-whitespace-normalization クラスを指定するとそのページの全てのコードブロックに対してプラグインを無効にできます。

また、このプラグインを有効にすると、コードブロック内の先頭や末尾に改行があれば削除してくれます。

Remove initial line feed というプラグインでもコードブロック内の先頭の改行を削除できますが、現在 DEPRECATED(非推奨)となっていて、こちらの Normalize Whitespace の使用が推奨されています。

以下がデフォルトの設定で、必要に応じて変更することができます。記述場所はダウンロードした JavaScript の読み込みの後(変数 Prism が参照できる場所)になります。

Prism.plugins.NormalizeWhitespace.setDefaults({
  'remove-trailing': true, // すべての行の末尾の空白を削除
  'remove-indent': true, // 余分なインデントを削除
  'left-trim': true, // コード ブロックの先頭からすべての空白を削除
  'right-trim': true, // コード ブロックの下部からすべての空白を削除
  /*'break-lines': 80,
  'indent': 2,
  'remove-initial-line-feed': false,
  'tabs-to-spaces': 4,
  'spaces-to-tabs': 4*/
});

Toolbar

Toolbar プラグインはコードブロックの右上にツールバーを表示します(toolbar クラスの div 要素を追加します)。但し、ボタンは自分で登録する必要があります

また、Show Language プラグインや Copy to Clipboard Button プラグインは Toolbar を利用しているので、それらを選択すると Toolbar プラグインも自動的に含まれます。

Toolbar プラグインはシンタックスハイライト表示する際に、対象の pre 要素を <div class="code-toolbar"></div> でラップし、pre 要素の後に <div class="toolbar"></div> を追加します。

そして、<div class="toolbar"></div> の中に <div class="toolbar-item"></div> でラップしたラベルやボタンを配置します。ラベルのテキストは <span> でマークアップされます。

以下は Toolbar プラグインを入れてある場合に変換されて出力されるマークアップの例です(開発ツールで確認できます)。

この例では Show Language と Copy to Clipboard Button プラグインが入っているので、そのラベルとボタンが出力されています。

<div class="code-toolbar">
  <pre class="language-css" tabindex="0">
    <code class="language-css">...</code>
  </pre>
  <div class="toolbar">
    <div class="toolbar-item"><!-- Show Language プラグインのラベル-->
      <span>CSS</span>
    </div>
    <div class="toolbar-item"><!-- Copy to Clipboard Button プラグインのボタン-->
      <button class="copy-to-clipboard-button" type="button" data-copy-state="copy">
        <span>Copy</span>
      </button>
    </div>
  </div>
</div>

ツールバーのスタイルは div.code-toolbar>.toolbar などのセレクタを使って設定できます。

div.code-toolbar>.toolbar {
  opacity: 1;
}

div.code-toolbar>.toolbar .toolbar-item {
  margin-right: .5rem;
}

div.code-toolbar>.toolbar .toolbar-item span,
div.code-toolbar>.toolbar .toolbar-item a {
  display: inline-block;
  padding: 0.2em 0.4em;
  border-bottom-left-radius: 0;
  border-bottom-right-radius : 0;
  border-top-left-radius : 0;
  border-top-right-radius: 0;
}

data-label 属性(ラベルの表示)

pre 要素に data-label 属性を追加すると、Toolbar プラグインはその属性の値を読み取り、ツールバーにラベル(値の文字列)を追加します

<pre data-label="ラベル"><code class="lang-css">p { color: red }</code></pre>

以下のコード上にマウスオーバーするとツールバーが表示されます。この例では上記で指定したラベルと、Show Language の言語のラベル、及び Copy to Clipboard Button のコピーボタンが表示されます。

p { color: red }

例えばファイル名を data-label 属性に指定することで、ファイル名を表示することができます。

また、独自にファイル名を表示するための属性を設定してファイル名を表示することもできます。

data-url 属性(リンクの表示)

data-label 属性と共に data-url 属性を追加すると、data-url 属性の値を href 属性の値としたリンク付きのラベルがツールバーに追加されます。

以下は見やすいように pre タグの中で code タグを改行しています。以下をそのまま記述すると空白文字がが挿入されてしまいます(Normalize Whitespace を入れていれば余分な空白文字は削除されます)。

<pre data-label="リンク" data-url="https://example.com">
  <code class="lang-css">p { color: red }</code>
</pre>

上記によりツールバーにリンクが表示されます(マウスオーバーするすると表示されます)。

p { color: red }

template 要素の利用

ラベルに任意の HTML を使用する場合は、ラベルに必要な HTML を含む template 要素を作成し、template 要素の id 属性の値を data-label 属性に指定します。

以下では、pre 要素の data-label 属性に template 要素の id の値 my-label-button を指定しています。

<pre data-label="my-label-button"><code class="lang-css">p { color: red }</code></pre>

template 要素は以下のような構造になります。また、template 要素は表示されないので任意の場所に記述できます。

<template id="data-label属性に指定する値">ラベルに表示するHTML</template>

以下の場合、クリックするとアラート表示するボタンをラベルに表示します。他のボタンと表示(適用されるスタイル)を合わせるため、span 要素でラベルをラップしています。

<template id="my-label-button">
  <button onclick="alert('Hello!');"><span>Click Me!</span></button>
</template>

上記は以下のように onclick イベントハンドラを template 内に別途定義することもできます。

<template id="my-label-button">
  <button id="my" onclick="hello();"><span>Click Me!</span></button>
  <script>
    function hello() {
      alert('Hello!');
    }
  </script>
</template>

以下のようにマウスオーバーするすると Click Me! というラベルのボタンが表示されます。

p { color: red }

以下は target や class 属性などを持つリンクをラベルに表示する例です。

<pre data-label="my-external-link"><code class="lang-css">p { color: red }</code></pre> 
<template id="my-external-link">
  <a href="https://example.com" target="_blank" rel="noopener" class="icon-box-arrow">External Link</a>
</template>

以下にマウスオーバーすると External Link というラベルのリンクが表示されます。アイコンの表示はクラス(.icon-box-arrow)にスタイルを設定しています。

p { color: red }
registerButton 関数

ボタンやラベルをツールバーに登録するための関数 Prism.plugins.toolbar.registerButton() が公開されています。この関数を使うと全てのツールバーにボタンやラベルを追加することができます。

この registerButton() は以下の2つの引数を受け取ります。

引数 説明
key string 表示するボタンやラベルを内部的に識別するための任意の文字列
opts ButtonOptions | Function ボタンを生成するためのオプションオブジェクト(ButtonOptions)、または表示する要素(DOM オブジェクト)を返す関数

ButtonOptions は以下のプロパティがあり、これらを指定することで表示する要素(DOM オブジェクト)が生成されます。

ボタンを表示する場合は、onClick プロパティにコールバック関数(リスナー)を指定し、リンクを表示する場合は onClick プロパティは指定せずに url プロパティにリンク先 URL の文字列を指定します。

プロパティ 説明
text ボタンまたはラベルのテキスト(表示する文字列)。※ 必須
url リンクの URL 文字列。このプロパティを設定すると a 要素(リンク)が作成され、href 属性に指定された文字列が設定されます。onClick プロパティに関数を指定すると、リンクは作成されません(無視されます)。
onClick ボタンのクリックイベントのリスナー。このプロパティにコールバック関数を指定すると button 要素が作成され、クリックイベントリスナーに指定した関数が設定されます。コールバック関数は引数に env というオブジェクトを受け取ります。
className ボタンやラベルの要素に指定するクラス名

onClick プロパティに指定するコールバック関数や registerButton() の第2引数に指定する関数は、引数に以下のようなプロパティを持つオブジェクト env を受け取ります。

プロパティ 説明
code その code 要素のテキストコンテンツ
element その code 要素(DOM オブジェクト)
grammar その code 要素の Grammar オブジェクト(?)
highlightedCode その code 要素のシンタックスハイライト表示される部分のマークアップ
language その code 要素に language-xxxx クラスで指定した言語(xxxx の部分)

以下は registerButton() の第2引数に ButtonOptions を指定してボタンをツールバーに表示する例です。

以下を記述すると、ツールバーに Hello というラベルのボタンが表示され、クリックするとシンタックスハイライト表示しているコードブロックの言語名がアラート表示されます。そしてアラートボックスの OK をクリックすると、コンソールに引数 env が出力されます。

Prism.plugins.toolbar.registerButton('hello', {
  text: 'Hello', // ボタンのテキスト(必須)
  onClick: (env) => { // イベントリスナー関数(オプション)
    alert('このコードの言語は ' + env.language + 'です。');
    console.log(env);  // コールバックの引数に渡される env をコンソールに出力
  }
});

特定の pre 要素にのみボタンをツールバーに追加

以下は registerButton() の第2引数に関数を指定する例です。

前述の例の場合、全てのコードのツールバーにボタンが表示されますが、以下は pre 要素に showHello というクラスが指定されている場合にのみ Hello というラベルのボタンを表示します。

第2引数に指定する関数の引数には env を受け取るので、env.element.parentElement で pre 要素を取得できます。また、第2引数に指定する関数では、ツールバーに表示する要素を返す必要があります。

Prism.plugins.toolbar.registerButton('hello2', (env) => {
  // この code 要素の親要素(pre 要素)を取得(env.element は <code>)
  const pre = env.element.parentElement;
  // pre 要素が取得できなければ終了
  if (!pre) { return; }
  // pre 要素のクラスを取得
  const preClassList = pre.classList;
  // 取得したクラスに showHello が含まれなければ終了
  if(!preClassList.contains('showHello')) { return; }
  // button 要素を作成
  const button = document.createElement('button');
  // ボタンのラベル
  button.innerHTML = '<span>Hello</span>';
  // ボタンにクリックイベントのリスナーを設定
  button.addEventListener('click', () => {
    alert('このコードの言語は ' + env.language + 'です。');
    console.log(env);
  });
  // 作成したボタン(button 要素)を返す
  return button;
});

ファイル名を表示するラベルを追加

デフォルトで、data-label 属性に指定したテキストがラベルとしてツールバーに表示されるようになっているので、data-label 属性にファイル名を指定すれば表示されます。

以下は、独自に data-file 属性が指定されていればその値をラベルとしてツールバーに表示し、data-file-url 属性も指定されていればリンクとして表示する例です。

Prism.plugins.toolbar.registerButton('file-name', function (env) {
  const pre = env.element.parentElement;
  if (!pre) { return; }
  // pre 要素に data-file 属性が設定されていなければ終了
  if (!pre.hasAttribute('data-file')) { return; }
  // data-file 属性の値を取得
  const text = pre.getAttribute('data-file');
  // 表示する要素の初期化
  let element;
  // data-file-url が設定されていればリンクを作成
  if (pre.hasAttribute('data-file-url')) {
    element = document.createElement('a');
    element.href = pre.getAttribute('data-file-url');
  } else {
    // data-file-url がなければ span 要素を作成
    element = document.createElement('span');
  }
  // 表示する要素のテキスト(ラベル)に data-file 属性の値を設定
  element.textContent = text;
  // span 要素に code-file-name クラスを追加
  element.classList.add('code-file-name')
  return element;
});

使用例

<pre data-file="foo.css" data-file-url="#foo">
  <code class="lang-css">p { color: red }</code>
</pre>

表示結果

  p { color: red }

key が重複した場合

registerButton() の第1引数の key が重複した場合、コンソールに警告が表示されます。

以下はすでにデフォルトで使用されている label という key を指定した場合に表示される警告の例です。

template 要素の利用

以下は registerButton() の第2引数の関数で、別途用意した template 要素を参照してボタンに表示する例です。以下がボタンに表示する span 要素及び SVG をコンテンツに持つ template 要素です。

<template id="my-svg-span">
  <span>
    <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" fill="yellow" viewBox="0 0 16 16">
      <path d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z"/>
      <path d="M4.285 9.567a.5.5 0 0 1 .683.183A3.498 3.498 0 0 0 8 11.5a3.498 3.498 0 0 0 3.032-1.75.5.5 0 1 1 .866.5A4.498 4.498 0 0 1 8 12.5a4.498 4.498 0 0 1-3.898-2.25.5.5 0 0 1 .183-.683zM7 6.5C7 7.328 6.552 8 6 8s-1-.672-1-1.5S5.448 5 6 5s1 .672 1 1.5zm4 0c0 .828-.448 1.5-1 1.5s-1-.672-1-1.5S9.448 5 10 5s1 .672 1 1.5z"/>
    </svg>
  </span>
</template>

第2引数の関数では、template 要素を ID を使って取得しています。template 要素が取得できない場合は終了します。

template 要素のコンテンツを cloneNode() を使用して複製する際は、引数に true を指定します(content 以下の全要素をコピー)。

ボタン要素を作成し、複製したコンテンツをに追加してイベントリスナーを設定して返しています。

Prism.plugins.toolbar.registerButton('hello3', (env) => {
  // template 要素を取得
  const template = document.getElementById('my-svg-span');
  // template 要素が取得できなければ終了
  if (!template) return;
  // template 要素のコンテンツを cloneNode() を使用して複製
  const span = template.content.cloneNode(true);
  // button 要素を作成
  const button = document.createElement('button');
  // button 要素に template 要素のコンテンツを追加
  button.appendChild(span);
  // button 要素にイベントリスナーを設定
  button.addEventListener('click', () => {
    alert('このコードの言語は ' + env.language + 'です。');
    console.log(env);
  });
  // 作成したボタン(button 要素)を返す
  return button;
});

以下は template 要素に button のマークアップを記述する場合の例です。

<template id="my-btn">
  <button><span>Click</span></button>
</template>

この場合、template 要素のコンテンツを複製したものは DocumentFragment のインスタンスなのでイベントリスナーを設定しても機能しないため、 firstElementChild で最初の子要素を取得しています。

Prism.plugins.toolbar.registerButton('hello4', (env) => {
  // template 要素を取得
  const template = document.getElementById('my-btn');
  if (!template) return;
  // template 要素のコンテンツを複製して firstElementChild で最初の子要素を取得
  const button = template.content.cloneNode(true).firstElementChild;
  // または const button = template.content.firstElementChild.cloneNode(true);
  button.addEventListener('click', () => {
    alert('このコードの言語は ' + env.language + 'です。');
    console.log(env);
  });
  return button;
});

関連項目:template 要素

ボタンの表示順

デフォルトでは、ボタンは登録された順序でツールバーに追加されます。 順序を制御する必要がある場合は、data-toolbar-order 属性を使用します。

data-toolbar-order 属性にボタン名のカンマ区切りリストを指定すると、これらのボタンが指定された順序で表示されるようになります。

※ リストにないボタンは表示されません(この方法を使用してボタンを無効することができます)。

以下は data-label 属性のラベル(label)、Show Language プラグインの出力(show-language)、独自に設定したラベル(file-name)、Copy to Clipboard Button プラグインのコピーボタン(copy-to-clipboar)の順番で表示する例です。

<pre
  data-label="Sample"
  data-file="foo.css"
  data-toolbar-order="label, show-language, file-name, copy-to-clipboard"
><code class="lang-css">p { color: red }</code></pre>

上記は以下のように表示されます。

p { color: red }

この設定も継承されるので、body 要素に data-toolbar-order 属性を指定すれば、ページ全体のボタンの表示順を設定することができます。

<body data-toolbar-order="label, show-language, file-name, copy-to-clipboard">

Show Language

Show Language プラグインを使うと、自動的にコードブロックの言語名をツールバーに表示します。

必要に応じて <pre> タグに data-language 属性を指定してその値を表示させることもできます。

<pre data-language="SVG1.1"><code class="lang-svg">
  省略
</code></pre>
<svg width="400" height="300" viewBox="0 0 400 300" >
  <circle cx="200" cy="150" r="50"/>
</svg>

Copy to Clipboard Button

Copy to Clipboard Button プラグインはクリックするとコードブロックをクリップボードにコピーするボタンを自動的に追加します。

デフォルトでは、プラグインはメッセージを英語で表示し、クリック後に 5 秒のタイムアウトを設定します。 次の data-* 属性(カスタムデータ属性)を使用して、デフォルト設定をオーバーライドできます。

カスタムデータ属性 説明
data-prismjs-copy デフォルトのメッセージ(ラベル)
data-prismjs-copy-error コピーに失敗した後に表示されるメッセージ。Ctrl+C を押すようユーザーに促します。
data-prismjs-copy-success コピーが成功した後に表示されるメッセージ
data-prismjs-copy-timeout コピー後のタイムアウト (ミリ秒単位)。 タイムアウトが経過すると、成功またはエラーメッセージはデフォルトのメッセージに戻ります。 値は負ではない整数である必要があります。

これらの設定は継承されるので、例えば、body 要素に設定するとそのページの全てのツールバーに反映されます。以下は日本語でラベルとメッセージを表示する例です。

<!DOCTYPE html>
<html lang="ja">
<head>
<!-- 中略 -->
</head>
<body
  data-prismjs-copy="コピー"
  data-prismjs-copy-error="コピーに失敗しました"
  data-prismjs-copy-success="コピーしました"
>
<!-- 以下省略 -->

Match braces

Match braces プラグインはコード中の対応するカッコ({} () [])を強調表示します。

このプラグインを有効にするには、<code> タグに match-braces クラスを追加します。

language-xxxx クラスなどと同様に、match-braces クラスは継承されるので、このクラスを <body> に追加して、ページ全体でプラグインを有効にすることもできます。

<pre><code class="language-xxxx match-braces">...</pre></code>

このプラグインは、カーソルがカッコの1つの上にあると、そのペアを強調表示します。

また、カッコの1つをクリックしてペアを選択して強調表示することもできます。 ペアの選択を解除するには、コードブロック内の任意の場所をクリックするか、別のペアを選択します。

function map(arr: number[], callback:(val: number) => number): number[] {
  const result: number[] = [];
  for(const elem of arr) {
    result.push(callback(elem));
  }
  return result;
}

const data = [1, 2, 3, 4];
const result = map(data, (x)=> x*2);
console.log(result);  //  [2, 4, 6, 8]

no-brace-hover クラス

<code> タグに no-brace-hover クラスを追加することでホバー効果を無効にできます。 このクラスは継承することもできます。

no-brace-select クラス

<code> タグに no-brace-select クラスを追加することでペアの選択を無効にできます。 このクラスは継承することもできます。

rainbow-braces クラス

<code> タグに rainbow-braces クラスを追加することで以下のようにカッコの色をレインボーカラーにできます。

function map(arr: number[], callback:(val: number) => number): number[] {
  const result: number[] = [];
  for(const elem of arr) {
    result.push(callback(elem));
  }
  return result;
}

const data = [1, 2, 3, 4];
const result = map(data, (x)=> x*2);
console.log(result);  //  [2, 4, 6, 8]

Command Line

Command Line プラグインを使うと、プロンプトを含むコマンドラインを表示し、オプションでコマンドからの出力/応答を表示することができます。

このプラグインを有効にするには、<pre> タグに command-line クラスを追加し、出力部分の行(プロンプトや強調表示なし)を data-output 属性で指定します。

<pre class="command-line" data-output="2"><code class="lang-bash">nvm --version
0.39.1</code></pre>

上記は以下のように表示されます。data-output="2" としているので、2行目はプロンプトや強調表示なしとなります。

nvm --version
0.39.1

<pre> タグにカスタムデータ属性 data-* を指定して、プロンプトなどの表示を変更することができます。

<pre class="command-line" data-prompt="project %" data-output="2-9"><code class="lang-bash">nvm install --lts
Installing latest LTS version.
・・・中略・・・
Now using node v18.17.1 (npm v9.6.7)</code></pre>

上記は以下のように表示されます。

nvm install --lts
Installing latest LTS version.
Downloading and installing node v18.17.1...
Downloading https://nodejs.org/dist/v18.17.1/node-v18.17.1-darwin-x64.tar.xz...
####################################################### 100.0%
Computing checksum with shasum -a 256
Checksums matched!
Now using node v18.17.1 (npm v9.6.7)
カスタムデータ属性 説明
data-output 出力として表示される行 (プロンプトや強調表示なし) を指定。
  • data-output="2" :2行目を出力として表示
  • data-output="2-5" :2行目から5行目を出力として表示
  • data-output="1,3" :1行目と3行目を出力として表示
  • data-output="1-2, 5, 7-9":1〜2行目と5行目、7〜9行目を出力として表示
data-user プロンプト [user@localhost] $ の user 部分を指定。この値に root を指定すると、プロンプト文字は # になり、その他の値では $ になります。それ以外(例 %)にするには data-prompt 属性でプロンプト全体を指定する必要があります。
data-host プロンプト [user@localhost] $ の localhost 部分を指定
data-prompt プロンプト全体

data-filter-output

いくつかの行を出力(プロンプトや強調表示なし) として自動的に表示するには、それらの行に任意の文字列をプレフィックスとして付け、<pre> 要素の data-filter-output 属性を使用してプレフィックスに使用する文字列を指定します。

例えば、data-filter-output="(out)"(out)で始まる行を出力として扱い、プロンプトや強調表示なしで表示し、指定したプレフィックス文字 (out) を表示から除外します。この場合、(out)の前にスペースなどがあると、(out)はプレフィックスとしてみなされません。

<pre class="command-line" data-filter-output="(out)" data-user="root"><code class="lang-bash">nvm --version
(out)Installing latest LTS version.
(out)Downloading and installing node v18.17.1...
(out)Downloading https://nodejs.org/dist/v18.17.1/node-v18.17.1-darwin-x64.tar.xz...

上記は以下のように表示されます。

nvm install --lts
(out)Installing latest LTS version.
(out)Downloading and installing node v18.17.1...
(out)Downloading https://nodejs.org/dist/v18.17.1/node-v18.17.1-darwin-x64.tar.xz...
テキストの選択

デフォルトでは [user@localhost] などのプロンプト部分のテキストはユーザーが選択できないようになっていますが、出力行に指定した部分のテキストはユーザーが選択可能になっています。

出力行部分もユーザーが選択できないようにするには以下を CSS に追加します。

.command-line span.token.output {
  user-select: none;
}

Copy to Clipboard Button プラグインを入れている場合、コピーボタンをクリックすると、プロンプト部分はコピーされないようになっています。

上記を設定すると、出力行部分を選択できないようにしますが、コピーボタンをクリックすると出力部分もコピーされます。

複数行コマンド

複数行のコマンドを処理するために以下のようなカスタムデータ属性が用意されています。

カスタムデータ属性 説明
data-continuation-str 行継続文字列/文字を設定。例:bash の場合 data-continuation-str="\"
data-continuation-prompt コマンドが最初の行を超えて継続したときに表示されるプロンプト(セカンダリプロンプト)を定義します。例:MySQL の場合、data-continuation-prompt="->"。 この属性が設定されていない場合は、デフォルトの > が使用されます。
data-filter-continuation すべての継続行の先頭に data-filter-continuation の値を付けると、data-continuation-prompt に設定されたプロンプトとともに表示されます。例えば、data-filter-continuation="(con)" は、(con) で始まる行を継続行として扱い、プレフィックス(con) を削除します(data-filter-output と同様の方法で機能します)。

複数行にまたがるコマンドを表示するには、以下の2つの方法があります。

行継続文字列を設定(bash など)

bash や zsh などでは、引数を改行で区切って入力するには、改行したい位置でバックスラッシュ\(行継続文字)を入力し return を押すと、プロンプトがセカンダリプロンプト>に変わります。

このような表示は、pre 要素に data-continuation-str 属性を使って行継続文字(列)を指定します。

以下は bash(zsh)の例です。pre 要素に data-continuation-str="\" を設定し、行継続文字列を\としているので、末尾に\ のある行で改行すると、デフォルトのセカンダリプロンプト>が表示されます。

<pre class="command-line"
  data-filter-output="(out)"
  data-prompt="foo %"
  data-continuation-str="\"><code class="lang-bash">echo \
apple \
banana
(out)apple banana</code></pre>

上記は以下のように表示されます。

echo \
apple \
banana
(out)apple banana

継続行に指定するプレフィックスを設定(SQL、Scala など)

MySQL など継続文字列/文字を持たない言語の場合は、継続行にプレフィックスを付けます。

継続行を表すプレフィックスは任意の文字列を data-filter-continuation 属性の値に指定します。

行を超えて継続したときに表示されるプロンプト(セカンダリプロンプト)は data-continuation-prompt 属性の値に指定します。

以下の例では、継続行を表すプレフィックスは data-filter-continuation="(con)" でプレフィックス文字列を (con) とし、セカンダリプロンプトは data-continuation-prompt="->" で -> としています。

<pre class="command-line"
  data-prompt="mysql>"
  data-continuation-prompt="->"
  data-filter-output="(out)"
  data-filter-continuation="(con)"><code class="language-sql">set @my_var = 'foo';
set @my_other_var = 'bar';
(out)
CREATE TABLE people (
(con)first_name VARCHAR(30) NOT NULL,
(con)last_name VARCHAR(30) NOT NULL
(con));
(out)Query OK, 0 rows affected (0.09 sec)
(out)
insert into people
(con)values ('John', 'Doe');
(out)Query OK, 1 row affected (0.02 sec)</code></pre>

上記は以下のように表示されます。

set @my_var = 'foo';
set @my_other_var = 'bar';
(out)
CREATE TABLE people (
(con)first_name VARCHAR(30) NOT NULL,
(con)last_name VARCHAR(30) NOT NULL
(con));
(out)Query OK, 0 rows affected (0.09 sec)
(out)
insert into people
(con)values ('John', 'Doe');
(out)Query OK, 1 row affected (0.02 sec)

Treeview

Treeview プラグインはファイルシステムのツリー構造にフォルダやファイルのアイコンを表示します。

code 要素に言語クラス language-treeview または lang-treeview を指定するとツリー構造にアイコンを表示してくれます。

ファイルのアイコンは拡張子によっては自動的に適切なアイコンが表示されます。

フォルダ(ディレクトリ)と認識させるにはフォルダ名の最後に / を付けます。

<pre><code class="language-treeview">tsp (ルート)/
├── dist
│   └── index.js
├── file.txt
├── sample.jpg
├── manual.pdf
├── node_modules/
├── document.docx
├── package.json
├── src/
│   └── index.ts
└── tsconfig.json
</code></pre>

上記は以下のように表示されます。

tsp (ルート)/
├── dist
│   └── index.js
├── file.txt
├── sample.jpg
├── manual.pdf
├── node_modules/
├── document.docx
├── package.json
├── src/
│   └── index.ts
└── tsconfig.json

tree コマンドを使う場合、-F オプションを指定するとフォルダに自動的に / が付くので便利です。

Prism themes(テーマページ)

ダウンロードページで選択できる8つのテーマ以外にも、以下の Github ページからテーマをダウンロードして使用することもできます。

PrismJS / prism-themes

但し、これらのテーマにはプラグインのスタイルは含まれていないので、プラグインを使用する場合は、ダウンロードページからダウンロードした CSS のプラグイン部分をコピーして追加する必要があります。