> ## 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.

# Backfill Rendering Mode

> Render backfill ads predictably with the right container pattern.

<Info>
  Available in Adrop Web SDK **1.2.3** or later.
</Info>

## TL;DR

For most slots, copy this pattern:

```html theme={null}
<!-- Mobile-friendly 320×100 banner slot -->
<div
  data-adrop-unit="YOUR_UNIT_ID"
  data-adrop-backfill-mode="fixed"
  style="width: 100%; aspect-ratio: 320 / 100;"
></div>
```

This single pattern gives you:

* **Responsive width** — the slot fills the device width on any screen
* **Locked height** — `aspect-ratio` derives the height from the width, so no CLS
* **Predictable rendering** — `fixed` mode stretches the backfill ad to the container exactly

The two ingredients are **`backfillMode: fixed`** and **`aspect-ratio` (inline)** matching the registered unit size (`320/100`, `300/250`, `728/90`, …).

<Note>
  **Prerequisite**: this snippet assumes `Adrop.observe({ appId: 'YOUR_APP_ID' })` has been called somewhere on the page. While developing, replace `YOUR_UNIT_ID` with `PUBLIC_TEST_UNIT_ID_320_100` to see a live test ad. For SDK install and initialization, see the [Banner Ads](/sdk/web/banner) or [CDN](/sdk/web/cdn) guides.
</Note>

***

## When to Use Which Mode

| Mode                   | Behavior                                                                                                                                                                                       | Use it when                                                                                              |
| ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- |
| `fixed`                | Stretches the backfill ad to fill the container (`width:100%; height:100%`). The publisher defines the slot size — by `aspect-ratio` for responsive width, or `height` for pixel-pinned slots. | You know the slot's size or ratio and want the ad to fit exactly. **Recommended for most banner slots.** |
| `responsive` (default) | The backfill network picks the ad size that best fits the container width. The SDK reserves a safe `min-height` automatically if the container has no size intent.                             | You don't want to commit to a size up front. The network gets the widest pick from its inventory.        |

<Note>
  Both modes are CLS-safe when the container has an inline size intent (`aspect-ratio`, `height`, `min-height`, or `max-height`). The difference is whether the publisher or the network decides the height.
</Note>

<Warning>
  `fixed` mode follows the container's height directly. If the container has no `aspect-ratio` or `height` defined, the ad collapses to 0px and becomes invisible — always pair `fixed` with a height intent.
</Warning>

***

## Container Patterns

Pick the pattern that matches your slot. All three work with both direct and backfill ads.

### Pattern A. Responsive width + locked ratio (recommended)

The slot fills the available horizontal width, and `aspect-ratio` derives the height from the unit's registered size. Best for mobile-first layouts and content feeds.

```html theme={null}
<!-- 320 × 100 mobile banner ratio -->
<div data-adrop-unit="YOUR_UNIT_ID"
     data-adrop-backfill-mode="fixed"
     style="width: 100%; aspect-ratio: 320 / 100;"></div>

<!-- 300 × 250 medium rectangle ratio -->
<div data-adrop-unit="YOUR_UNIT_ID"
     data-adrop-backfill-mode="fixed"
     style="width: 100%; aspect-ratio: 300 / 250;"></div>

<!-- 728 × 90 leaderboard ratio -->
<div data-adrop-unit="YOUR_UNIT_ID"
     data-adrop-backfill-mode="fixed"
     style="width: 100%; aspect-ratio: 728 / 90;"></div>
```

Use the **aspect-ratio that matches the unit's registered size**. The container's height is `width × (ratio.h / ratio.w)`, and `fixed` mode tells the SDK to fill that exact box.

<Note>
  If you need to cap the width, base the cap on **your own design (content column, sidebar width, etc.)** — not on the registered ad size. Pinning `max-width` to the registered pixel size shrinks the ad on wider screens and reduces revenue. As long as the ratio is preserved, the backfill ad fills the container at any width.
</Note>

### Pattern B. Fixed pixel height (pixel-precise alignment)

Use this when the slot must align pixel-by-pixel with other content (a docked header, sidebar, sticky footer).

```html theme={null}
<div data-adrop-unit="YOUR_UNIT_ID"
     data-adrop-backfill-mode="fixed"
     style="width: 100%; height: 100px;"></div>
```

### Pattern C. SDK auto-reservation (no size committed)

Use this when you don't want to commit to a size — the SDK reserves a safe `min-height` based on the container width to keep CLS low, and the backfill network picks the best inventory match.

```html theme={null}
<div data-adrop-unit="YOUR_UNIT_ID"
     style="width: 100%;"></div>
```

This is the default behavior. No `data-adrop-backfill-mode` attribute needed.

***

## Specifying the Mode

The narrowest scope wins:

```
request option > HTML attribute > global config > default ('responsive')
```

**Per-slot (declarative)**

```html theme={null}
<div data-adrop-unit="YOUR_UNIT_ID"
     data-adrop-backfill-mode="fixed"
     style="width: 100%; aspect-ratio: 320 / 100;"></div>
```

**Per-slot (programmatic)**

```js theme={null}
await Adrop.instance().renderAd(container, {
  unit: 'YOUR_UNIT_ID',
  backfillMode: 'fixed',
})
```

**Publisher-wide default**

```js theme={null}
Adrop.observe({
  appId: 'YOUR_APP_ID',
  backfillMode: 'fixed',
})
```

***

## Size Intent Must Be Inline

The SDK reads only these four **inline** properties as size intent:

* `height`
* `min-height`
* `max-height`
* `aspect-ratio`

If any of them is present inline, the SDK preserves the publisher's layout and skips auto-reservation.

<Note>
  All other styles — width, padding, margin, color, border, shadow, transition, etc. — can use CSS classes or Tailwind freely. Only those four size-intent properties need to be inline.
</Note>

### Recommended

```html theme={null}
<!-- aspect-ratio inline, everything else via class -->
<div data-adrop-unit="YOUR_UNIT_ID"
     data-adrop-backfill-mode="fixed"
     class="w-full max-w-[640px] rounded-xl bg-gray-100 shadow-sm"
     style="aspect-ratio: 300 / 250;"></div>

<!-- height inline, everything else via class -->
<div data-adrop-unit="YOUR_UNIT_ID"
     data-adrop-backfill-mode="fixed"
     class="w-full bg-gray-50 rounded border"
     style="height: 90px;"></div>
```

### Not Recommended

```html theme={null}
<!-- Size intent pinned only through CSS class / Tailwind -->
<div data-adrop-unit="YOUR_UNIT_ID"
     class="w-full aspect-[300/250] rounded-xl"></div>

<div data-adrop-unit="YOUR_UNIT_ID"
     class="w-full h-[100px]"></div>

<!-- Size intent only via styled-components / CSS module -->
<StyledAdSlot data-adrop-unit="YOUR_UNIT_ID" />
```

<Warning>
  The SDK cannot see sizes pinned through CSS classes. In `responsive` mode, auto-reservation runs in parallel with the class-driven height and may extend the container beyond what you intended.
</Warning>

**How to fix (pick one):**

1. **Move size intent to inline style (recommended)**

   ```html theme={null}
   <div data-adrop-unit="YOUR_UNIT_ID"
        class="w-full rounded-xl"
        style="aspect-ratio: 300 / 250;"></div>
   ```

2. **Opt into `fixed` to disable auto-reservation**

   ```html theme={null}
   <div data-adrop-unit="YOUR_UNIT_ID"
        data-adrop-backfill-mode="fixed"
        class="w-full aspect-[300/250]"></div>
   ```

***

## CLS and Auto-Reservation

**What is CLS?** Cumulative Layout Shift happens when a late-arriving ad pushes the rest of the content down. A button users were about to tap suddenly moves, causing misclicks. It also affects search ranking and ad revenue.

**How `responsive` mode handles it:** when the container has no inline size intent, the SDK reserves a safe `min-height` based on the container width.

* If the actual ad is **larger** than the reserved value, the container expands naturally (the jump is just smaller).
* If the actual ad is **smaller**, the empty space remains (no jump occurs).
* Only `min-height` is set — never `max-height` — so there is no overflow risk.

If you express height or aspect-ratio inline, the SDK skips auto-reservation entirely — your layout wins.

***

## Auto-Refresh

Once a backfill ad loads successfully, the SDK manages refresh automatically — you don't need to configure or call anything.

* **Visibility-gated**: refresh counts only while the container is at least 50% visible and the page tab is active
* **Bounded**: refreshes stop after a fixed maximum count per slot
* **Self-cleaning**: when the container is removed from the DOM, refresh is unregistered automatically

Every successful refresh fires an `AD_RECEIVED` event with `format: 'backfill'`.

***

## When No Backfill Is Available

If neither a direct ad nor a backfill ad can be served, the SDK emits the `AD_BACKFILL_NO_FILL` event. Listen for it to hide the slot or render fallback content.

```js theme={null}
Adrop.instance().on(Adrop.Events.AD_BACKFILL_NO_FILL, (unit) => {
  // Hide the slot or render fallback content
})
```

For the full event lifecycle, see the [Banner Ads](/sdk/web/banner) guide.

***

## Upgrading to 1.2.3

| Container state                               | Impact                                                                                                                                                                            |
| --------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Inline** `height` / `aspect-ratio` present  | No change (existing behavior preserved)                                                                                                                                           |
| **No** size intent                            | Empty-space jump is reduced via auto-reservation. Ad behavior unchanged.                                                                                                          |
| Size intent only via **CSS class / Tailwind** | **Action required** — auto-reservation may extend the container. Before upgrading, see [Not Recommended](#not-recommended) and either move the intent inline or opt into `fixed`. |

The default mode is `responsive`, so most upgrades are safe with no code change. To freeze the pre-1.2.3 layout, add a single `fixed` opt-in (globally or per-slot).

***

## Related Guides

<CardGroup cols={2}>
  <Card title="Banner Ads (React)" href="/sdk/web/banner">
    Implement banner ads in React
  </Card>

  <Card title="Banner Ads (CDN)" href="/sdk/web/cdn-banner">
    Implement banner ads via CDN
  </Card>

  <Card title="Reference" href="/sdk/web/reference">
    BackfillMode type definition
  </Card>
</CardGroup>
