# Widget customization reference

> Every LayerHop embed URL parameter, its range and default, the matching @layerhop/widget option, the postMessage events and the setParams contract (embed protocol 1.1).

Source: https://docs.layerhop.com/widget-reference

The LayerHop widget is the swap card served at `https://layerhop.com/embed`, configured entirely through URL parameters and reporting back to your page with `postMessage` events. This page lists every parameter, option and event of embed protocol **1.1** (`ready.version` is `1.1.0`); for a step-by-step setup see [Embed the widget](/guides/embed-widget), or design it visually in the [widget builder](https://layerhop.com/developers/widget).

## How are parameters validated?

Each parameter is checked on its own. The embed ignores an invalid value and uses that parameter's default, so a typo never breaks the card. The contract is additive: parameters and events are only ever added, never renamed or removed.

The `@layerhop/widget` package is stricter: `buildEmbedUrl()`, `mount()` and `<LayerHopWidget />` throw a `LayerHopWidgetError` on an invalid option, so integration mistakes show up during development.

| Value type | Format |
|---|---|
| Color | Hex without `#`, 3 or 6 digits (`0af`, `22d3ee`). The package also accepts a leading `#` and strips it. |
| Flag | `1` turns it on. Omit the parameter to leave it off (`showUsd=0` is the one flag that turns something off). |
| Chain | A chain slug (`base`) or numeric id (`8453`). Solana's id is `7565164`. See [Supported chains](/chains). |
| Token | A symbol from the token list (`USDC`), or a contract address / Solana mint. |
| List | Comma-separated values, no spaces needed (`base,arbitrum`). |

## Swap parameters

These are the same parameters as a [swap deep link](/guides/deep-links).

| Param | Example | Meaning |
|---|---|---|
| `srcChain` | `base` | Chain the user pays from. |
| `srcToken` | `USDC` | Token the user pays with. |
| `dstChain` | `solana` | Chain the user receives on. |
| `dstToken` | `SOL` | Token the user receives. |
| `amount` | `100` | Amount in **human units** (decimal string, `.` separator), not base units. |
| `recipient` | `9WzD…` | Prefilled destination address. Editable, with a warning when it is not the connected wallet, unless `lockRecipient=1`. |
| `slippageBps` | `50` | Slippage tolerance in basis points (integer, 0–10000). |
| `defaultSlippage` | `50` | Alias of `slippageBps`; `slippageBps` wins when both are set. |
| `integrator` | `myapp` | Your partner id, `[a-z0-9-]{1,32}`. Attribution, plus your [partner fee](/guides/partner-fees) when the id is a registered partner. Unknown ids are ignored. |

The embed always quotes on the `widget` [fee channel](/concepts/fees-and-channels) (0.30% LayerHop fee). A registered partner's fee is added on top and shown as its own line.

## Theme parameters

| Param | Values | Default | Meaning |
|---|---|---|---|
| `theme` | `dark`, `light`, `auto` | `dark`, or the preset's default | `auto` follows the visitor's `prefers-color-scheme`. |
| `preset` | `midnight`, `paper`, `lime`, `ocean`, `mono` | none | A full palette for dark and light mode. `paper` defaults to light, the others to dark. Explicit colors override it. |
| `accent` | color | theme | Buttons and highlights. |
| `accentText` | color | automatic | Text on the accent. If it would read below 4.5:1 against the accent, the embed uses dark ink or white instead. |
| `bg` | color | transparent | Page background behind the card. Presets never set it. |
| `surface` | color | theme | Card background. |
| `surfaceAlt` | color | theme | Fields and nested panels. |
| `text` | color | theme | Main text. |
| `textMuted` | color | theme | Secondary text. |
| `border` | color, `0` or `1` | theme | A hex value sets the border color. `0` removes the card outline, `1` makes it stronger. |
| `success` | color | theme | Links, success states and the secondary accent. |
| `warning` | color | theme | Warnings. |
| `danger` | color | theme | Errors. |
| `radius` | 0–40 (px) | theme | Card corner radius. |
| `radiusInner` | 0–32 (px) | theme | Field and button corner radius. |
| `font` | `inter`, `system`, `space-grotesk`, `ibm-plex-sans`, `dm-sans`, `manrope` | theme | `ibm-plex-sans`, `dm-sans` and `manrope` load from Google Fonts only when chosen. |
| `fontScale` | 0.875–1.125 | `1` | Scales the whole card. |
| `density` | `compact`, `comfortable` | `comfortable` | `compact` tightens fields and the main button. |
| `width` | 320–720 (px) | `480` | Maximum card width. |
| `shadow` | `none`, `soft`, `strong` | theme | Card shadow. |

Focus rings always use a color with at least 3:1 contrast on the card: the accent, then `success`, then `text`.

## Content and behaviour parameters

| Param | Example | Meaning |
|---|---|---|
| `title` | `Deposit to Acme` | Header text, plain text up to 32 characters. Longer values are ignored. |
| `logo` | `https://acme.xyz/logo.svg` | Header image, shown at 24 × 24 px. Absolute `https` URL without credentials; loaded with `referrerpolicy=no-referrer` and hidden if it fails. |
| `hideHeader` | `1` | Hides the header (title, wallet button, history, settings). Wallets connect from the main button. |
| `buttonLabel` | `Deposit` | Main button label once the swap is ready to review, up to 24 characters. |
| `showUsd` | `0` | Hides USD values (default `1`). |
| `fromChains` | `base,arbitrum` | Only these chains on the pay side. |
| `toChains` | `solana` | Only these chains on the receive side. |
| `excludeChains` | `bsc` | Never offer these chains, on either side. |
| `fromTokens` | `base:USDC,USDT` | Only these tokens on the pay side: `chain:addressOrSymbol` entries, or a bare symbol for any allowed chain. With only `chain:`-qualified entries, the side's chains are limited to the ones named. |
| `toTokens` | `base:USDC` | Same, for the receive side. |
| `lockSrc` | `1` | The pay chain and token can't be changed. |
| `lockDst` | `1` | The receive chain and token can't be changed. |
| `lockAmount` | `1` | The amount can't be edited. |
| `lockRecipient` | `1` | With a valid `recipient`, the recipient is fixed and the receive side stays on that address's VM (EVM or Solana). Ignored without a valid `recipient`. |
| `hideRoutes` | `1` | Shows only the selected route's summary, not the alternatives. |
| `hideSettings` | `1` | Hides the slippage settings. |
| `hideHistory` | `1` | Hides the history panel. |
| `hidePoweredBy` | `1` | Hides "Routed by LayerHop". Needs `integrator`, and applies once a quote confirms it is a registered partner. |
| `locale` | `en` | Interface language. Only `en` today; anything else falls back to `en`. |
| `allowParentOrigin` | `https://acme.xyz` | The one origin allowed to send [`setParams`](#how-does-the-host-page-control-the-widget) messages. `https` only (`http` for localhost), no path. |

When an allow-list or a locked recipient rules out the linked or default tokens, the card starts on the first allowed asset. Allow-lists also apply to wallet-based defaults, the flip button and `setParams`.

## How do package options map to URL parameters?

`@layerhop/widget` options use the URL parameter names, with these exceptions:

| Package option | URL parameter | Why |
|---|---|---|
| `headerTitle` | `title` | `title` is the iframe's `title` attribute in `mount()`. |
| `borderColor` | `border` (hex) | `border` is the outline flag (`true` → `1`, `false` → `0`). |
| Booleans (`lockDst: true`) | `lockDst=1` | `showUsd: false` becomes `showUsd=0`. |
| Arrays (`fromChains: ["base", 42161]`) | `fromChains=base,42161` | |
| `liveUpdates: true` | `allowParentOrigin=<your origin>` | Set for you from `location.origin`. |

Options that only exist in the package (they never reach the URL):

| Option | Default | Meaning |
|---|---|---|
| `baseUrl` | `https://layerhop.com` | Origin (optionally with a path prefix) serving `/embed`. |
| `autoResize` | `true` | Resize the iframe height on `resize` events. |
| `height` | `640` | Initial iframe height in px, before the first `resize` event. |
| `maxWidth` | `480` px (or `width` + 16) | CSS `max-width` of the iframe. |
| `title` | `LayerHop swap` | The iframe's accessible title. |
| `liveUpdates` | `false` | Let `update()` apply amount, token, theme and color changes in place through `setParams`, without reloading. |
| `onReady`, `onQuote`, `onSubmitted`, `onStatus`, `onError`, `onResize`, `onRoutes`, `onWalletConnected`, `onWalletDisconnected`, `onAmountChanged` | none | One callback per [event](#which-events-does-the-widget-send). |
| `onEvent` | none | Called for every valid event, after the typed callback. |

For the `<script>` tag, every option is a kebab-case `data-` attribute on an element marked `data-layerhop-widget`: `srcChain` → `data-src-chain`, `borderColor` → `data-border-color`. Lists are comma-separated. A flag is on when the attribute is empty, `1`, `true` or `yes`, and off with `0`.

## Which events does the widget send?

The embed posts `{ source: "layerhop", type, payload }` to `window.parent` with target origin `"*"`. Payloads never contain secrets.

| `type` | Payload | When |
|---|---|---|
| `ready` | `{ version }` | The card has loaded. `version` is the protocol version, `1.1.0` today. |
| `quote` | `{ provider, srcChain, dstChain, amount, dstAmount }` | A new best quote is shown. |
| `routes` | `{ count, provider }` | Routes answered: how many, and the best route's provider. |
| `submitted` | `{ provider, srcChainId, srcTxHash }` | The user's wallet broadcast the source transaction. |
| `status` | `{ provider, srcTxHash, state }` | Order state changed: `pending`, `filled`, `refunded` or `failed`. |
| `error` | `{ code, message }` | Something failed. `code` is a stable [error code](/errors). |
| `resize` | `{ height }` | Content height in px changed. |
| `walletConnected` | `{ vm, address }` | A wallet connected. `vm` is `evm` or `svm`. |
| `walletDisconnected` | `{ vm, address }` | A wallet disconnected. |
| `amountChanged` | `{ amount, srcChain, srcToken }` | The user edited the amount (human units, `""` when cleared; chain slug; token address). Debounced, about 400 ms. |

`routes`, `walletConnected`, `walletDisconnected` and `amountChanged` were added in protocol 1.1. With the script tag, each event is also dispatched on the host element as a bubbling DOM `CustomEvent` named `layerhop:<type>`, with the payload in `event.detail`.

Always check `event.data.source === "layerhop"` and, in production, `event.origin === "https://layerhop.com"`. A connected wallet address is public data, but `walletConnected` does tell your page which address connected.

## How does the host page control the widget?

Parent → embed messages are opt-in. The embed only listens when its URL has `allowParentOrigin`, and only accepts a message when `event.origin` equals that origin exactly and `event.source` is its parent window.

```js
iframe.contentWindow.postMessage(
  { source: "layerhop-host", type: "setParams", payload: { amount: "250", dstToken: "USDT", accent: "38bdf8" } },
  "https://layerhop.com",
);
```

| `type` | Payload keys (all optional) |
|---|---|
| `setParams` | `amount` (human units, `""` clears it), `srcChain`, `srcToken`, `dstChain`, `dstToken`, `theme`, `accent`, `accentText`, `bg`, `surface`, `surfaceAlt`, `text`, `textMuted`, `border`, `success`, `warning`, `danger` |

Other keys and invalid values are ignored. Locks and allow-lists still apply: a locked side or a locked amount ignores changes. The integrator, recipient, locks and fees can never be changed this way.

With the package, `mount(el, { liveUpdates: true })` sets `allowParentOrigin` for you, and `widget.update()` sends `setParams` for the live keys above and reloads the iframe only when another option changed.

## What iframe settings does the widget need?

| Setting | Value | Why |
|---|---|---|
| `color-scheme` (CSS) | `normal` | The embed page is transparent with a `normal` root color scheme. A different scheme on the iframe makes browsers paint an opaque white or black box behind the card. The package sets it. |
| `allow` | `clipboard-write` | Lets the user copy addresses and transaction hashes. |
| Height | `640` px to start, then follow `resize` events | The card grows when panels open. |
| `title` | Any descriptive text | Accessible name for screen readers. |
