テンプレートディレクティブの概要
Astroではテンプレートディレクティブと呼ばれる特別なHTML属性が用意されています。これらは主にAstroコンポーネント(.astroファイル)のテンプレート内で使えますが、一部は.mdxファイルでも使用可能です。
テンプレートディレクティブの役割は、要素やコンポーネントの挙動をコントロールすることです。例えば、開発をより楽にするコンパイラ機能(classの代わりにclass:listを使うなど)を有効にしたり、Astroコンパイラに特別な指示(client:loadでクライアントサイドの機能を有効にするなど)を出したりします。
このページでは、Astroで使えるすべてのテンプレートディレクティブとその働きについて詳しく解説します。
テンプレートディレクティブを正しく使うには、以下の2つの条件を満たす必要があります。
- 名前にコロン(:)を含めること。例えば「X:Y」のような形式です(例:
client:load)。 - コンパイラから認識できる位置に書くこと。例えば、
<X {...attr}>のように書いた場合、attrの中身にディレクティブがあってもコンパイラには見えないので注意が必要です。
テンプレートディレクティブの中には、独自の値を設定できるものもあります。例えば、
<X client:load />→ 値を設定する必要がありません<X class:list={['some-css-class']} />→ 配列を値として渡します。
なお、テンプレートディレクティブはコンポーネントの最終的なHTML出力には含まれません。あくまでAstroのビルド時に使われる特別な指示といえるでしょう。
よく使われるディレクティブ
Section titled “よく使われるディレクティブ”class:list
Section titled “class:list”class:list={...} は、複数のクラス値を配列で受け取り、それを一つのクラス文字列に変換します。この機能は、@lukeedの人気ライブラリ clsx を使って実現しています。
class:list で使える値の種類は以下の通りです。
- 文字列:そのまま要素のクラスとして追加されます
- オブジェクト:値が真のキーが要素のクラスとして追加されます
- 配列:中身を展開して処理します
false,null,undefined:無視されます
<!-- This --><span class:list={[ 'hello goodbye', { world: true }, [ 'friend' ] ]} /><!-- Becomes --><span class="hello goodbye world friend"></span>set:html
Section titled “set:html”set:html={string} は、HTML文字列を要素の中身として挿入します。これは el.innerHTML を使うのと似た動作をします。
注意:Astroは自動的にこの値をエスケープしません! 必ず信頼できる値を使うか、テンプレートに渡す前に手動でエスケープしてください。これを怠ると、クロスサイトスクリプティング(XSS)攻撃の危険性があります。
---const rawHTMLString = "Hello <strong>World</strong>"---<h1>{rawHTMLString}</h1> <!-- Output: <h1>Hello <strong>World</strong></h1> --><h1 set:html={rawHTMLString} /> <!-- Output: <h1>Hello <strong>World</strong></h1> -->また、set:html は <Fragment> でも使えるので、余分なラッパー要素を追加せずにHTMLを挿入できます。これはCMSからHTMLを取得する場合などに特に便利です。
---const cmsContent = await fetchHTMLFromMyCMS();---<Fragment set:html={cmsContent}>set:html={Promise<string>} を使うと、PromiseでラップされたHTML文字列を要素に挿入できます。
これは、データベースなどに保存されている外部のHTMLを挿入する際に役立ちます。
---import api from '../db/api.js';---<article set:html={api.getArticle(Astro.props.id)}></article>set:html={Promise<Response>} を使うと、Response オブジェクトの内容を要素に挿入できます。
これは主に fetch() を使う場合に便利です。例えば、以前の静的サイトジェネレーターで作成した古い記事を取得する際などに使えます。
<article set:html={fetch('http://example/old-posts/making-soup.html')}></article>set:html はどんなタグでも使えますし、必ずしもHTMLを含める必要はありません。例えば、ページに JSON-LD スキーマを追加したい場合、<script> タグ内で JSON.stringify() と組み合わせて使うこともできます。
<script type="application/ld+json" set:html={JSON.stringify({ "@context": "https://schema.org/", "@type": "Person", name: "Houston", hasOccupation: { "@type": "Occupation", name: "Astronaut" }})}/>define:vars
Section titled “define:vars”define:vars={...} を使うと、コンポーネントのフロントマターからクライアントの <script> や <style> タグに、サーバーサイドの変数を渡せます。JSON形式にできるフロントマター変数なら何でも使えます。Astro.props を通じてコンポーネントに渡された props も含みます。値は JSON.stringify() でシリアライズされます。
---const foregroundColor = "rgb(221 243 228)";const backgroundColor = "rgb(24 121 78)";const message = "Astroは素晴らしい!";---<style define:vars={{ textColor: foregroundColor, backgroundColor }}> h1 { background-color: var(--backgroundColor); color: var(--textColor); }</style>
<script define:vars={{ message }}> alert(message);</script><script> タグで define:vars を使うと、自動的に is:inline ディレクティブ が適用されます。つまり、スクリプトはまとめられずに、HTMLに直接埋め込まれます。
これは、Astroがスクリプトをまとめる際、そのスクリプトを一度だけ実行するようにしているためです。同じコンポーネントがページに複数回含まれていても、スクリプトは一度しか実行されません。しかし define:vars は、それぞれの値セットでスクリプトを再実行する必要があるため、Astroはインラインスクリプトを作成します。
スクリプトに変数を渡す場合は、代わりに手動で変数を渡す方法 (EN)を試してみてください。
高度なディレクティブ
Section titled “高度なディレクティブ”is:raw
Section titled “is:raw”is:raw は、Astroコンパイラにその要素の中身をテキストとして扱うよう指示します。これにより、その要素内ではAstroの特殊なテンプレート構文がすべて無視されます。
例えば、テキストをHTMLに変換するカスタムのKatexコンポーネントがある場合、ユーザーは以下のように使えます。
---import Katex from '../components/Katex.astro';---<Katex is:raw>ここには{構文}の衝突があります</Katex>