> ## Documentation Index
> Fetch the complete documentation index at: https://docs.adrop.io/llms.txt
> Use this file to discover all available pages before exploring further.

# バナー広告

> Reactでバナー広告を実装する方法をご案内します。

## 実装方法

バナー広告は2つの方法で実装できます。

| 方式              | 説明               | 推奨          |
| --------------- | ---------------- | ----------- |
| Data Attributes | HTML属性のみで簡単に実装   | 迅速な実装       |
| renderAd        | 広告読み込みタイミングを直接制御 | 細かい制御が必要な場合 |

<Note>
  開発環境ではテストユニットIDを使用してください：`PUBLIC_TEST_UNIT_ID_320_100`
</Note>

***

## 1. Data Attributes方式

最も簡単な方式で、`data-adrop-unit`属性を追加するだけでSDKが自動的に広告を読み込みます。

```tsx theme={null}
function BannerAd() {
  return (
    <div
      data-adrop-unit="YOUR_UNIT_ID"
      data-adrop-context-id="YOUR_CONTEXT_ID"
      data-adrop-theme="light"
      data-adrop-custom-click="true"  // カスタムクリック処理の有効化
    />
  );
}
```

### Data Attributes

<ParamField body="data-adrop-unit" type="string" required>
  Ad Controlコンソールで作成したユニットID
</ParamField>

<ParamField body="data-adrop-context-id" type="string">
  [コンテキストターゲティング](/ja/sdk/web/targeting#コンテキストターゲティング)用Context ID
</ParamField>

<ParamField body="data-adrop-theme" type="string" default="light">
  テーマ設定（`light`または`dark`） - [ダークモード設定](/ja/ad-unit/dark-mode)を参照
</ParamField>

<ParamField body="data-adrop-custom-click" type="boolean" default={false}>
  カスタムクリック処理の有効化 - `true`に設定するとSDKが自動で目的地URLに移動せず、`adClicked`イベントのみ発生させます。開発者がクリック動作を直接実装できます。
</ParamField>

<ParamField body="data-adrop-backfill-mode" type="string" default="responsive">
  バックフィル広告のレンダリングモード（`responsive` または `fixed`）。詳細は[バックフィルレンダリングモード](/ja/sdk/web/backfill)ガイドを参照してください。（SDK 1.2.3+）
</ParamField>

<ParamField body="data-adrop-ad-id" type="string">
  広告識別子 — **デバイスで表示**機能で登録済みテストデバイスからドラフトクリエイティブをプレビューするときに必要です。本番環境にハードコードしないでください。
</ParamField>

### 広告の再リクエスト

Reactのkeyを変更してコンポーネントを再マウントすると、広告が再リクエストされます。

```tsx theme={null}
function App() {
  const [adKey, setAdKey] = useState(0);

  const reloadAd = () => {
    setAdKey(prev => prev + 1);
  };

  return (
    <>
      <div key={adKey} data-adrop-unit="YOUR_UNIT_ID" />
      <button onClick={reloadAd}>広告を更新</button>
    </>
  );
}
```

***

## 2. renderAd方式

広告読み込みタイミングを直接制御したい場合に使用します。

```tsx theme={null}
import { useEffect, useRef } from 'react';
import { Adrop } from '@adrop/ads-web-sdk';

function BannerAd() {
  const containerRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    const adrop = Adrop.instance();

    if (containerRef.current) {
      adrop.renderAd(containerRef.current, {
        unit: 'YOUR_UNIT_ID',
        contextId: 'YOUR_CONTEXT_ID',
        theme: 'light',
        useCustomClick: true  // カスタムクリック処理の有効化
      });
    }

  }, []);

  return <div ref={containerRef} />;
}
```

### renderAdオプション

<ParamField body="unit" type="string" required>
  Ad Controlコンソールで作成したユニットID
</ParamField>

<ParamField body="uid" type="string">
  ユーザー識別子（SDK設定値を個別の広告枠で上書きする場合に使用）
</ParamField>

<ParamField body="contextId" type="string">
  [コンテキストターゲティング](/ja/sdk/web/targeting#コンテキストターゲティング)用Context ID
</ParamField>

<ParamField body="theme" type="string" default="light">
  テーマ設定（`light`または`dark`） - [ダークモード設定](/ja/ad-unit/dark-mode)を参照
</ParamField>

<ParamField body="useCustomClick" type="boolean" default={false}>
  カスタムクリック処理の有効化 - `true`に設定するとSDKが自動で目的地URLに移動せず、`adClicked`イベントのみ発生させます。開発者がクリック動作を直接実装できます。
</ParamField>

<ParamField body="backfillMode" type="'responsive' | 'fixed'" default="responsive">
  バックフィル広告のレンダリングモード。詳細は[バックフィルレンダリングモード](/ja/sdk/web/backfill)ガイドを参照してください。（SDK 1.2.3+）
</ParamField>

<ParamField body="adId" type="string">
  広告識別子 — **デバイスで表示**機能で登録済みテストデバイスからドラフトクリエイティブをプレビューするときに必要です。本番環境にハードコードしないでください。
</ParamField>

### 広告の再リクエスト

`renderAd()`を再度呼び出すと、広告が再リクエストされます。Data Attributesで作成した広告枠にも使用できます。

```tsx theme={null}
function BannerAd() {
  const containerRef = useRef<HTMLDivElement>(null);

  const reloadAd = () => {
    const adrop = Adrop.instance();
    if (containerRef.current) {
      adrop.renderAd(containerRef.current, {
        unit: 'YOUR_UNIT_ID'
      });
    }
  };

  return (
    <>
      <div ref={containerRef} />
      <button onClick={reloadAd}>広告を更新</button>
    </>
  );
}
```

<Note>
  Data Attributesで作成した広告枠に`renderAd()`を呼び出す場合、data attributesに存在しない項目や修正したい項目のみを渡せば十分です。
</Note>

### 広告の削除

`clear()`を呼び出してコンテナから広告を削除できます。

```tsx theme={null}
const adrop = Adrop.instance();
adrop.clear(containerRef.current);
```

***

## 広告サイズ

推奨：レスポンシブな幅 + ユニット登録サイズと一致する `aspect-ratio`。枠が端末幅に合わせて伸縮し、高さは比率で固定されるため CLS が発生しません。

```tsx theme={null}
<div
  data-adrop-unit="YOUR_UNIT_ID"
  data-adrop-backfill-mode="fixed"
  style={{ width: '100%', aspectRatio: '320 / 100' }}
/>
```

ピクセル単位の整列が必要な場合は固定ピクセルサイズもサポートします。

```tsx theme={null}
<div
  data-adrop-unit="YOUR_UNIT_ID"
  style={{ width: 320, height: 100 }}
/>
```

| 区分       | サイズ設定                                                | 配置      |
| -------- | ---------------------------------------------------- | ------- |
| ダイレクト広告  | レスポンシブ対応、高さ必須                                        | 水平/垂直中央 |
| バックフィル広告 | コンテナ幅に合わせて自動マッチ（`responsive`）またはコンテナ高さに合わせる（`fixed`） | 水平中央    |

<Note>
  バックフィル広告のコンテナ作成パターンとレンダリングモードの選択基準は[バックフィルレンダリングモード](/ja/sdk/web/backfill)ガイドを参照してください。
</Note>

***

## イベント処理

広告の状態変化を検出して、適切なUI処理ができます。

```tsx theme={null}
import { useEffect, useRef } from 'react';
import { Adrop } from '@adrop/ads-web-sdk';

function BannerAd({ unitId }: { unitId: string }) {
  const containerRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    const adrop = Adrop.instance();

    // 広告受信成功
    const handleReceived = (unit: string, adData: any) => {
      console.log('広告受信:', unit);
    };

    // 配信可能なダイレクト広告なし
    const handleNoFill = (unit: string) => {
      console.warn('広告なし:', unit);
    };

    // リクエスト失敗
    const handleFailed = (unit: string) => {
      console.error('広告失敗:', unit);
    };

    // インプレッション
    const handleImpression = (unit: string, adData: any) => {
      console.log('広告表示:', unit);
    };

    // クリック
    const handleClicked = (unit: string, adData: any) => {
      console.log('広告クリック:', unit);
    };

    // バックフィル広告なし
    const handleBackfillNoFill = (unit: string) => {
      console.warn('バックフィル広告なし:', unit);
    };

    // 動画再生開始
    const handleVideoStart = (unit: string, adData: any) => {
      console.log('動画開始:', unit);
    };

    // 動画再生完了
    const handleVideoEnd = (unit: string, adData: any) => {
      console.log('動画完了:', unit);
    };

    // 特定ユニットのみフィルタリング
    const filter = { unit: unitId };

    adrop.on(Adrop.Events.AD_RECEIVED, handleReceived, filter);
    adrop.on(Adrop.Events.AD_NO_FILL, handleNoFill, filter);
    adrop.on(Adrop.Events.AD_FAILED, handleFailed, filter);
    adrop.on(Adrop.Events.AD_IMPRESSION, handleImpression, filter);
    adrop.on(Adrop.Events.AD_CLICKED, handleClicked, filter);
    adrop.on(Adrop.Events.AD_BACKFILL_NO_FILL, handleBackfillNoFill, filter);
    adrop.on(Adrop.Events.AD_VIDEO_START, handleVideoStart, filter);
    adrop.on(Adrop.Events.AD_VIDEO_END, handleVideoEnd, filter);

    if (containerRef.current) {
      adrop.renderAd(containerRef.current, { unit: unitId });
    }

    return () => {
      adrop.off(Adrop.Events.AD_RECEIVED, handleReceived);
      adrop.off(Adrop.Events.AD_NO_FILL, handleNoFill);
      adrop.off(Adrop.Events.AD_FAILED, handleFailed);
      adrop.off(Adrop.Events.AD_IMPRESSION, handleImpression);
      adrop.off(Adrop.Events.AD_CLICKED, handleClicked);
      adrop.off(Adrop.Events.AD_BACKFILL_NO_FILL, handleBackfillNoFill);
      adrop.off(Adrop.Events.AD_VIDEO_START, handleVideoStart);
      adrop.off(Adrop.Events.AD_VIDEO_END, handleVideoEnd);
    };
  }, [unitId]);

  return <div ref={containerRef} />;
}
```

### サポートするイベント

| イベント     | 定数                    | 説明             |
| -------- | --------------------- | -------------- |
| 広告受信     | `AD_RECEIVED`         | 広告リクエスト成功      |
| 広告なし     | `AD_NO_FILL`          | 配信可能なダイレクト広告なし |
| リクエスト失敗  | `AD_FAILED`           | 広告リクエスト失敗      |
| インプレッション | `AD_IMPRESSION`       | 広告インプレッション記録   |
| クリック     | `AD_CLICKED`          | ユーザーが広告をクリック   |
| バックフィルなし | `AD_BACKFILL_NO_FILL` | バックフィル広告なし     |
| 動画開始     | `AD_VIDEO_START`      | 動画広告の再生開始      |
| 動画完了     | `AD_VIDEO_END`        | 動画広告の再生完了      |

<Note>
  コンポーネントのアンマウント時に必ず`off()`でイベントリスナーを解除してください。
</Note>

### AdData

イベントハンドラーで受け取る広告データです。詳細なフィールド情報は[リファレンス > AdData](/ja/sdk/web/reference#addata)を参照してください。

***

## カスタムクリック処理

`useCustomClick`が有効化されると、SDKが自動で目的地URLに移動しなくなります。代わりにクリックイベントを処理してカスタム動作を実装できます。

```tsx theme={null}
import { useEffect, useRef } from 'react';
import { Adrop } from '@adrop/ads-web-sdk';

function CustomClickBannerAd({ unitId }: { unitId: string }) {
  const containerRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    const adrop = Adrop.instance();
    const filter = { unit: unitId };

    // カスタム動作で広告クリック処理
    const handleClicked = (unit: string, adData: any) => {
      console.log('広告クリック:', unit);
      console.log('目的地URL:', adData.destinationURL);
      
      // カスタムクリック動作実装
      // 例: 確認ダイアログ表示、分析トラッキングなど
      const userConfirmed = confirm('広告主ページを訪問しますか？');
      if (userConfirmed && adData.destinationURL) {
        window.open(adData.destinationURL, '_blank');
      }
    };

    adrop.on(Adrop.Events.AD_CLICKED, handleClicked, filter);

    if (containerRef.current) {
      adrop.renderAd(containerRef.current, {
        unit: unitId,
        useCustomClick: true
      });
    }

    return () => {
      adrop.off(Adrop.Events.AD_CLICKED, handleClicked);
    };
  }, [unitId]);

  return <div ref={containerRef} />;
}
```

<Note>
  カスタムクリック処理が有効化されると、ユーザーが広告をクリックしたときの動作を完全に制御できます。`destinationURL`は`adClicked`イベントデータに含まれて提供されます。
</Note>

***

## 完全なサンプル

### BannerAd.tsx

```tsx theme={null}
import { useEffect, useRef } from 'react';
import { Adrop } from '@adrop/ads-web-sdk';

interface BannerAdProps {
  unitId: string;
  contextId?: string;
  theme?: 'light' | 'dark';
  onReceived?: (adData: any) => void;
  onFailed?: () => void;
  onClicked?: () => void;
}

function BannerAd({
  unitId,
  contextId,
  theme = 'light',
  onReceived,
  onFailed,
  onClicked
}: BannerAdProps) {
  const containerRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    const adrop = Adrop.instance();
    const filter = { unit: unitId };

    const handleReceived = (_: string, adData: any) => onReceived?.(adData);
    const handleFailed = () => onFailed?.();
    const handleClicked = () => onClicked?.();

    adrop.on(Adrop.Events.AD_RECEIVED, handleReceived, filter);
    adrop.on(Adrop.Events.AD_FAILED, handleFailed, filter);
    adrop.on(Adrop.Events.AD_CLICKED, handleClicked, filter);

    if (containerRef.current) {
      adrop.renderAd(containerRef.current, {
        unit: unitId,
        contextId,
        theme
      });
    }

    return () => {
      adrop.off(Adrop.Events.AD_RECEIVED, handleReceived);
      adrop.off(Adrop.Events.AD_FAILED, handleFailed);
      adrop.off(Adrop.Events.AD_CLICKED, handleClicked);

    };
  }, [unitId, contextId, theme]);

  return <div ref={containerRef} className="banner-ad-container" />;
}

export default BannerAd;
```

### 使用例

```tsx theme={null}
import BannerAd from './components/BannerAd';

function App() {
  return (
    <div>
      <header>
        <BannerAd
          unitId="HEADER_BANNER_UNIT_ID"
          onClicked={() => console.log('ヘッダーバナークリック')}
        />
      </header>

      <main>
        <h1>コンテンツ</h1>
      </main>

      <footer>
        <BannerAd
          unitId="FOOTER_BANNER_UNIT_ID"
          theme="dark"
        />
      </footer>
    </div>
  );
}
```

***

## バックフィル広告

バックフィル広告が有効な場合、直接広告がないときに自動的にバックフィル広告がリクエストされます。`adData.format`で広告タイプを区別できます。

```tsx theme={null}
import { useEffect, useRef } from 'react';
import { Adrop } from '@adrop/ads-web-sdk';

function BannerAd({ unitId }: { unitId: string }) {
  const containerRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    const adrop = Adrop.instance();
    const filter = { unit: unitId };

    // 広告受信（直接広告またはバックフィル）
    const handleReceived = (unit: string, adData: any) => {
      if (adData.format === 'backfill') {
        console.log('バックフィル広告がロードされました');
      } else {
        console.log('直接広告がロードされました');
      }
    };

    // 直接広告なし（バックフィルリクエスト開始）
    const handleNoFill = (unit: string) => {
      console.log('直接広告なし、バックフィル広告をリクエスト中...');
    };

    // バックフィル広告もなし
    const handleBackfillNoFill = (unit: string) => {
      console.warn('バックフィル広告もありません');
      // 広告エリアを非表示にするなどの処理
    };

    adrop.on(Adrop.Events.AD_RECEIVED, handleReceived, filter);
    adrop.on(Adrop.Events.AD_NO_FILL, handleNoFill, filter);
    adrop.on(Adrop.Events.AD_BACKFILL_NO_FILL, handleBackfillNoFill, filter);

    if (containerRef.current) {
      adrop.renderAd(containerRef.current, { unit: unitId });
    }

    return () => {
      adrop.off(Adrop.Events.AD_RECEIVED, handleReceived);
      adrop.off(Adrop.Events.AD_NO_FILL, handleNoFill);
      adrop.off(Adrop.Events.AD_BACKFILL_NO_FILL, handleBackfillNoFill);
    };
  }, [unitId]);

  return <div ref={containerRef} />;
}
```

<Note>
  **開発環境テスト**: アプリに連携された広告ユニットのうち少なくとも1つが**収益化中**であれば、localhostからでもバックフィル広告のリクエストが可能です。承認されていないドメインでは `AD_BACKFILL_NO_FILL` イベントが発生します。
</Note>
