astro-components

Astro コンポーネント

Astroコンポーネントは、Astroプロジェクトの基本的な構成要素です。HTMLテンプレートとサーバー側ロジックを組み合わせた、再利用可能なUI部品を作成できます。

Astroコンポーネントの構造

Astroコンポーネント(.astroファイル)は、frontmatterとテンプレートの2つの部分で構成されます。

---
// frontmatter: サーバー側で実行されるJavaScript/TypeScript
import Header from './Header.astro';

interface Props {
  title: string;
  description?: string;
}

const { title, description = 'デフォルトの説明' } = Astro.props;
---
<!-- テンプレート: HTMLとJSX風の構文 -->
<article>
  <h2>{title}</h2>
  <p>{description}</p>
</article>

Props

コンポーネントにPropsを渡すことができます。TypeScriptを使用する場合はPropsインターフェースを定義できます。

---
interface Props {
  title: string;
  isActive?: boolean;
}

const { title, isActive = false } = Astro.props;
---
<button class:list={[{ active: isActive }]}>
  {title}
</button>

使用側:

---
import Button from './Button.astro';
---
<Button title="送信" isActive={true} />

スロット(Slot)

スロットを使用すると、子コンテンツを受け取ることができます。

基本的なスロット

---
// Card.astro
---
<div class="card">
  <slot />
</div>

使用側:

---
import Card from './Card.astro';
---
<Card>
  <h2>カードのタイトル</h2>
  <p>カードの内容</p>
</Card>

名前付きスロット

複数のスロットを定義できます:

---
// Layout.astro
---
<div class="layout">
  <header>
    <slot name="header" />
  </header>
  <main>
    <slot />  <!-- デフォルトスロット -->
  </main>
  <footer>
    <slot name="footer" />
  </footer>
</div>

使用側:

---
import Layout from './Layout.astro';
---
<Layout>
  <h1 slot="header">サイトタイトル</h1>
  
  <p>メインコンテンツ(デフォルトスロット)</p>
  
  <p slot="footer">© 2025</p>
</Layout>

Island Architecture とクライアントディレクティブ

Astroの特徴であるIsland Architectureを実現するため、UIフレームワークのコンポーネント(React、Vue、Svelte等)を部分的にハイドレーションできます。

クライアントディレクティブ

ディレクティブ説明
client:loadページ読み込み時に即座にハイドレーション
client:idleブラウザがアイドル状態になったらハイドレーション
client:visible要素がビューポートに入ったらハイドレーション
client:mediaメディアクエリが一致したらハイドレーション
client:onlyサーバー側レンダリングをスキップし、クライアントのみでレンダリング

使用例

---
import Counter from './Counter.jsx';  // Reactコンポーネント
import Carousel from './Carousel.vue';  // Vueコンポーネント
---
<!-- ページ読み込み時に即座にインタラクティブに -->
<Counter client:load />

<!-- ビューポートに入ったらハイドレーション(遅延読み込み) -->
<Carousel client:visible />

<!-- アイドル時にハイドレーション -->
<Counter client:idle />

<!-- 特定のメディアクエリでハイドレーション -->
<Counter client:media="(max-width: 768px)" />

<!-- クライアントのみでレンダリング(SSRスキップ) -->
<Counter client:only="react" />

ディレクティブなしの場合

UIフレームワークのコンポーネントをclient:ディレクティブなしで使用すると、サーバー側でHTMLとしてレンダリングされ、クライアントJavaScriptは送信されません(静的HTML出力)。

---
import Card from './Card.jsx';
---
<!-- 静的HTMLとして出力、インタラクティブ性なし -->
<Card title="静的カード" />

class:list ディレクティブ

条件付きでクラスを適用する便利な構文です:

---
const { isActive, isDisabled, size } = Astro.props;
---
<button class:list={[
  'btn',
  { active: isActive },
  { disabled: isDisabled },
  size && `btn-${size}`,
]}>
  クリック
</button>

set:html ディレクティブ

HTMLを直接挿入する場合に使用します(XSSに注意):

---
const rawHtml = '<strong>太字テキスト</strong>';
---
<div set:html={rawHtml} />

コンポーネントの配置

コンポーネントは通常src/components/ディレクトリに配置しますが、任意の場所に配置可能です。

src/
├── components/
│   ├── Header.astro
│   ├── Footer.astro
│   └── ui/
│       ├── Button.astro
│       └── Card.astro
├── layouts/
│   └── BaseLayout.astro
└── pages/
    └── index.astro

参考