> For the complete documentation index, see [llms.txt](https://docs.swapper.finance/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.swapper.finance/widget-integration/modal-and-embed.md).

# Modal & Inline Embed

Two presentations built on top of [`SwapperIframe`](/widget-integration/iframe-sdk.md): a centered **modal** popup, and an **inline embed** that reveals a preloaded widget over a placeholder for an instant open. Both live in `@swapper-finance/deposit-sdk`.

## Modal — `SwapperModal` / `openSwapperModal`

A modal overlay with a backdrop, CSS animations, escape / click-outside to close, and body-scroll locking.

### Quick open

```typescript
import { openSwapperModal } from "@swapper-finance/deposit-sdk";

const modal = openSwapperModal({
  integratorId: "your-id",
  dstChainId: "8453",
  dstTokenAddr: "0x833…913",
  depositWalletAddress: "0x2A0…28A",
  onClose: () => console.log("Modal closed"),
});

// close programmatically
modal.close();
```

### The class API

For more control, use `SwapperModal` directly:

```typescript
import { SwapperModal } from "@swapper-finance/deposit-sdk";

const modal = new SwapperModal({
  integratorId: "your-id",
  dstChainId: "8453",
  dstTokenAddr: "0x833…913",
  depositWalletAddress: "0x2A0…28A",
  onClose: () => console.log("closed"),
});

modal.open();
modal.isModalOpen();      // → boolean
modal.getIframe();        // → underlying SwapperIframe
modal.updateConfig({ /* patch */ });
modal.close();            // hide (widget stays loaded), route back to home
modal.destroy();          // full teardown
```

`close()` **hides** the modal but keeps the widget loaded for an instant reopen, and tells the widget to return to its home screen so the next `open()` starts fresh rather than resuming the previous selection.

### `modalStyle`

Style the modal chrome (distinct from the [widget's own styling](/widget-integration/styling.md)):

| Field          | Default             | Description          |
| -------------- | ------------------- | -------------------- |
| `width`        | `"450px"`           | Modal width.         |
| `height`       | `"560px"`           | Modal height.        |
| `overlayColor` | `"rgba(0,0,0,0.7)"` | Backdrop color.      |
| `borderRadius` | `"30px"`            | Modal corner radius. |
| `zIndex`       | `10000`             | Stacking order.      |

The widget renders its own close button inside the modal (and the modal closes on its `close_request`), so there is no separate modal-level close-button option — style the button via the [widget theme](/widget-integration/styling.md).

### Flexible height

The modal auto-enables the widget's flexible home-page height: the home screen scales to its content (instead of the fixed 560px), and the modal smoothly animates to match (clamped to 90% of the viewport). Users with `prefers-reduced-motion` get an instant snap. Nothing to configure.

## Preloading the modal

Build the modal hidden and load the widget in the background so the first `open()` is instant:

```typescript
import { preloadSwapperModal } from "@swapper-finance/deposit-sdk";

// when your page mounts
const modal = preloadSwapperModal({
  integratorId: "your-id",
  dstChainId: "8453",
  dstTokenAddr: "0x833…913",
  depositWalletAddress: "0x2A0…28A",
});

// later, on user action — opens instantly
button.addEventListener("click", () => modal.open());
```

Equivalent to `new SwapperModal({ ..., preload: true })` or calling `modal.preload()`.

If something changed between preload and open (say the deposit address), pass a patch to `open()` — it's applied to the live widget right before it becomes visible:

```typescript
modal.open({ depositWalletAddress: "0x...newAddress" });
```

`updateConfig(patch)` and `updateSigner(signer)` are also exposed directly and are safe to call before the modal has been built.

{% hint style="info" %}
Preload loads the widget but holds smart-wallet authorization until the first `open()`.
{% endhint %}

## Inline embed — `SwapperEmbed`

For widgets that live in the page layout (not a modal) but should still open instantly. The iframe loads immediately on a hidden `position: fixed` host; `showIn(target)` moves the host over the target element's box, so the already-loaded widget appears there with no reload.

```typescript
import { preloadSwapperEmbed } from "@swapper-finance/deposit-sdk";

// when your page mounts — starts loading in the background
const embed = preloadSwapperEmbed({
  integratorId: "your-id",
  dstChainId: "8453",
  dstTokenAddr: "0x833…913",
  depositWalletAddress: "0x2A0…28A",
});

// later — the widget appears over the placeholder instantly
button.addEventListener("click", () => embed.showIn("#widget-placeholder"));

embed.hide();     // widget stays loaded, routes back to home
embed.destroy();  // full teardown
```

The target is a **placeholder**: size it to the box the widget should occupy (e.g. `450px × 560px`). The host mirrors the target's drawable box — rect, corner radii, border widths, and stacking position — and follows it across scrolling, resizes, and size changes. The iframe is never reparented in the DOM (that would force a reload).

Pass `flexibleHeight: true` to let the home page auto-scale; the embed animates the *placeholder's* height so your page layout reflows with it.

Like the modal, smart-wallet authorization is deferred until the first `showIn()`.

## Which one?

* **A button that pops a dialog** → `openSwapperModal`.
* **The same, but instant** → `preloadSwapperModal`.
* **A widget that sits in your layout and opens instantly** → `preloadSwapperEmbed`.
* **Full manual control over an inline iframe** → [`SwapperIframe`](/widget-integration/iframe-sdk.md).
