Skip to content
Cloud AI エンジニア入門ガイド
Go back

03. .astroコンポーネントの基本

この章の全体像として、二層構造、Props、slot、クライアント処理の4つを番号順に並べ、部品を組み合わせてページを作れるようになることを示した図

シリーズ目次前章: 02. Astroの環境構築とプロジェクト構成次章: 04. Astroのレイアウトとスタイリング

Table of contents

Open Table of contents

この章のねらい

Astroでサイトを作るとき、いちばん多く書くのが .astro ファイルです。文法と、どこでいつ実行されるのかを押さえます。

.astro はHTMLの上位互換として作られています。正しいHTMLはそのまま .astro として通りますし、そこに機能がいくつか上乗せされているだけ、と考えると入りやすいはずです。

コンポーネントの二層構造

.astro ファイルは、大きく2つの部分に分かれます。

---
// ここがコンポーネントスクリプト(フロントマター)
const title = "はじめてのAstro";
const items = ["りんご", "みかん", "ぶどう"];
---

<!-- ここがコンポーネントテンプレート -->
<h1>{title}</h1>
<ul>
  {items.map(item => <li>{item}</li>)}
</ul>

上の3本のハイフン(---)で囲まれた部分がコンポーネントスクリプト、その下がコンポーネントテンプレートです。この区切りは「コードフェンス」と呼ばれます。

2つの層は、実行される場所も届き方も違います。

astroファイルが3本のハイフンで囲まれたコンポーネントスクリプトとその下のコンポーネントテンプレートに分かれ、前者はサーバーでのみ実行されてブラウザに送られず、後者がHTMLとして出力されることを示した図

コンポーネントスクリプト

コードフェンスの中には、通常のJavaScript(またはTypeScript)を書きます。ここでできることの例です。

このコードはサーバー側でしか実行されず、ブラウザには送信されません。ビルド時(静的生成の場合)かリクエスト時(オンデマンドレンダリングの場合)に実行され、その結果だけがHTMLとして届きます。

Astroコンポーネントがサーバー側でスクリプトを実行しHTMLを組み立て、完成したHTMLだけがブラウザに送られる流れを示した図

この性質のおかげで、APIキーを使った外部API呼び出しやデータベースアクセスをコンポーネント内に直接書いても、その内容が利用者のブラウザに漏れることはありません。

---
// この処理はサーバーでのみ実行される
const response = await fetch("https://api.example.com/posts");
const posts = await response.json();
---

<ul>
  {posts.map(post => <li>{post.title}</li>)}
</ul>

コードフェンス内では await をそのまま使えます(トップレベルawait)。データ取得のために特別なフックや関数を覚える必要はありません。

コンポーネントテンプレート

テンプレートはHTMLですが、次の追加機能が使えます。

記法意味
{式}JavaScriptの式を評価して埋め込む
{条件 && <p>表示</p>}条件つきで要素を出す
{配列.map(...)}配列から要素を繰り返し生成する
<Component />他のコンポーネントを呼び出す
class:list={...}条件に応じてクラス名を組み立てる

見た目はJSXに似ていますが、.astro のテンプレートの土台はHTMLです。classclassName に書き換える必要はありませんし、コメントも <!-- --> がそのまま通ります。

コンポーネントを組み合わせる

作ったコンポーネントは、インポートしてタグとして使います。

---
// src/pages/index.astro
import Card from "../components/Card.astro";
---

<main>
  <Card title="お知らせ" />
  <Card title="製品情報" />
</main>

インポートしたコンポーネント名は大文字で始めるのが慣例です(小文字だと通常のHTMLタグと区別がつかなくなるため)。

Props:外から値を受け取る

コンポーネントに値を渡すには、HTMLの属性と同じ書き方をします。受け取る側は Astro.props を使います。

---
// src/components/Card.astro
interface Props {
  title: string;
  description?: string;
}

const { title, description = "説明はありません" } = Astro.props;
---

<article class="card">
  <h2>{title}</h2>
  <p>{description}</p>
</article>

Props という名前でインターフェースを定義しておくと、Astroがそれを型として拾い、呼び出し側で補完とチェックが効きます。分割代入のデフォルト値で省略時の値を決められますし、? を付けた項目は任意、付けなければ必須になります。

文字列以外を渡すときは波かっこを使います。

<Card title="製品情報" tags={["新着", "特集"]} count={3} />

slot:中身を差し込む

Propsは「値」を渡す仕組みですが、「HTMLのかたまり」を渡したいこともあります。そのための仕組みが <slot /> です。

---
// src/components/Panel.astro
---

<section class="panel">
  <slot />
</section>

呼び出し側でタグの中に書いた内容が、<slot /> の位置に入ります。

<Panel>
  <h2>タイトル</h2>
  <p>本文です。</p>
</Panel>

名前付きスロット

差し込み口が複数必要なときは、name 属性で区別します。

---
// src/components/Layout.astro
---

<div class="wrapper">
  <header>
    <slot name="header" />
  </header>
  <main>
    <slot />
  </main>
  <footer>
    <slot name="footer" />
  </footer>
</div>

呼び出し側は slot="名前" 属性で対応づけます。

<Layout>
  <h1 slot="header">サイト名</h1>
  <p>本文はここに入ります。</p>
  <small slot="footer">© 2026</small>
</Layout>

name を持たない <slot /> は「その他すべて」の受け皿になります。

呼び出し側とコンポーネント側の対応は次のとおりです。

呼び出し側でslot属性を付けた要素がコンポーネント側の同じ名前のslotへ差し込まれ、slot属性を持たない要素は名前なしのslotに入ることを、左右の対応で示した図

フォールバックコンテンツ

スロットに何も渡されなかったときの既定値を、<slot> の中に書いておけます。

<slot name="header">
  <h1>既定のタイトル</h1>
</slot>

コンテンツが渡されればそちらが優先され、渡されなければ既定値が表示されます。

クライアント側で動くスクリプト

コンポーネントスクリプトはサーバーでしか動かないため、ボタンのクリックに反応するようなコードは <script> タグに書きます。

<button id="toggle">切り替え</button>

<script>
  document.getElementById("toggle")?.addEventListener("click", () => {
    document.body.classList.toggle("dark");
  });
</script>

テンプレート内の <script> は、既定でAstroによってバンドル・最適化されます。処理させたくない場合は is:inline ディレクティブを付けると、書いたままの形でHTMLに出力されます。

なお、<script> の中からコンポーネントスクリプトの変数を直接参照することはできません。両者は実行される場所も時点も違うためです。値を渡したいときは、data-* 属性を経由するのが定石です。

サーバーで動くコンポーネントスクリプトの変数をブラウザで動くscriptタグから直接参照することはできず、data-属性としてHTMLに出力してdatasetから読み取ることで値を渡す流れを示した図

---
const message = "こんにちは";
---

<button id="greet" data-message={message}>あいさつ</button>

<script>
  const button = document.getElementById("greet");
  button?.addEventListener("click", () => {
    alert(button.dataset.message);
  });
</script>

より本格的な対話機能が必要な場合は、ReactやSvelteのコンポーネントをアイランドとして持ち込む方法があります。これは08. AstroのアイランドアーキテクチャとUIフレームワークで扱います。

HTMLの厳密さに注意(Astro 7)

Astro 7では .astro のコンパイラがRustで書き直され、不正なHTML構文に対して以前より厳しくなりました。具体的には、次のようなコードがエラーになります。

一方、<p> の中に <div> を置くような、構文上は閉じていても意味的に不正なネストはコンパイルエラーになりません。以前のコンパイラはこの手のHTMLを黙って直していましたが、Astro 7はそのまま出力してブラウザのHTMLパーサーに投げます。レイアウトが意図せず崩れるので、エディタのフォーマッタと astro check を通したうえで、生成結果も自分の目で見てください。

要点

参考資料


シリーズ目次前章: 02. Astroの環境構築とプロジェクト構成次章: 04. Astroのレイアウトとスタイリング


Share this post:

Previous Post
04. Astroのレイアウトとスタイリング
Next Post
02. Astroの環境構築とプロジェクト構成