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

# DepositElement

> Funds a Whop account. Renders an amount field and the account's live funding rails — crypto (a per-network deposit address with its QR) and bank transfer (the wire fields for each settlement currency) — resolved from the account id with no credentials, so it works on any page. Pass `savedCards`, `allowNewCard`, or `showPlatformBalance` to offer rails you settle yourself: the element collects the amount and the choice, then emits `cardDepositRequested` / `addCardRequested` / `platformBalanceSelected` and waits for you to call `showStep({ step: 'amount' })` when your own screen is done.

Belongs to the [`Wallet`](/sdk/elements/wallet/overview) group. Render `<DepositElement />` inside it (React), or call `wallet.create('deposit', { … })` on the handle (vanilla) — consumer props and `on<Event>` callbacks both go in the create options / JSX props.

<Note>This element can be mounted **inline** (`create`) or opened as a **modal** overlay (`createOverlay`).</Note>

## Preview

A live, interactive demo of this element with sample data:

<div data-whop-demo-shell style={{ position: "relative", minHeight: "320px", transition: "min-height 200ms ease" }}>
  <div data-whop-demo-skeleton style={{ position: "absolute", inset: "0", borderRadius: "12px", background: "rgba(140, 140, 140, 0.12)", pointerEvents: "none", transition: "opacity 200ms ease" }} />

  <iframe data-whop-demo src="https://js.whop.cloud/elements/amber/wallet/deposit/en/demo/index.html" title="DepositElement demo" height="320" allow="payment; publickey-credentials-get; clipboard-write" style={{ position: "relative", width: "100%", border: "0", borderRadius: "12px", background: "transparent", colorScheme: "normal" }} />
</div>

## Usage

<div data-whop-usage="wallet/deposit">
  <CodeGroup>
    ```tsx React theme={null}
    import { WhopElements, Wallet, DepositElement } from "@whop/elements-react";
    import { loadWhop } from "@whop/elements";

    function Example() {
      return (
        <WhopElements elements={loadWhop()}>
          <Wallet /* options */>
            <DepositElement onDepositInitiated={(payload) => console.log("depositInitiated", payload)} onCardDepositRequested={(payload) => console.log("cardDepositRequested", payload)} onAddCardRequested={(payload) => console.log("addCardRequested", payload)} onBankSelected={(payload) => console.log("bankSelected", payload)} onPlatformBalanceSelected={(payload) => console.log("platformBalanceSelected", payload)} onDepositConfirmed={(payload) => console.log("depositConfirmed", payload)} onStepChanged={(payload) => console.log("stepChanged", payload)} onDismissed={(payload) => console.log("dismissed", payload)} />
          </Wallet>
        </WhopElements>
      );
    }
    ```

    ```html Vanilla theme={null}
    <script src="https://js.whop.cloud/elements/amber/elements.js" data-whop-elements></script>
    <script type="module">
      const wallet = window.WhopElements().wallet.create({ /* options */ });
      wallet.create('deposit', {
        onDepositInitiated: (payload) => console.log("depositInitiated", payload),
        onCardDepositRequested: (payload) => console.log("cardDepositRequested", payload),
        onAddCardRequested: (payload) => console.log("addCardRequested", payload),
        onBankSelected: (payload) => console.log("bankSelected", payload),
        onPlatformBalanceSelected: (payload) => console.log("platformBalanceSelected", payload),
        onDepositConfirmed: (payload) => console.log("depositConfirmed", payload),
        onStepChanged: (payload) => console.log("stepChanged", payload),
        onDismissed: (payload) => console.log("dismissed", payload)
      }).mount('#wallet-deposit');
    </script>
    ```
  </CodeGroup>
</div>

## Props

<ResponseField name="amount" type="string">
  Prefill the amount and make it read-only — for flows that already know what is owed. An amount at or below zero, or above 9,999,999, is ignored. Defaults to `""`.
</ResponseField>

<ResponseField name="showCrypto" type="boolean">
  Offer the crypto rail when the account has a deposit address. Defaults to `true`.
</ResponseField>

<ResponseField name="showBank" type="boolean">
  Offer the bank-transfer rail when the account has wire instructions. Defaults to `true`.
</ResponseField>

<ResponseField name="savedCards" type="DepositSavedCard[]">
  Cards you already hold for this payer, rendered as funding rows. Choosing one emits `cardDepositRequested` with the amount — the element never charges a card. Defaults to `[]`.
</ResponseField>

<ResponseField name="allowNewCard" type="boolean">
  Add an "Add card" row that emits `addCardRequested` so you can open your own card-collection flow. Defaults to `false`.
</ResponseField>

<ResponseField name="showPlatformBalance" type="boolean">
  Offer a "Platform balance" row that emits `platformBalanceSelected` immediately, with no amount step. Defaults to `false`.
</ResponseField>

<ResponseField name="cardFee" type="DepositCardFee | null">
  Processing fees to preview under the amount when a card row is selected. `percentageFee` is in percentage POINTS (`2.9` is 2.9%); `fixedFee` and `radarFee` are major units (`0.3` is \$0.30). Defaults to `null`.
</ResponseField>

<ResponseField name="preferredMethodId" type="string">
  Preselect a rail by id (`bank`, `crypto`, `platform_balance`, or a saved card id). Continue stays disabled while that rail is not yet offered, rather than funding through another one. Defaults to `""`.
</ResponseField>

<ResponseField name="deferBankToHost" type="boolean">
  Emit `bankSelected` and stay on the amount screen instead of showing the wire fields — for hosts that run their own step (a verification, an onboarding) first. Because that host owns the rail, the row is then offered even before the account has instructions to show. Defaults to `false`.
</ResponseField>

<ResponseField name="confirmCryptoDeposit" type="boolean">
  Show an "I have deposited my funds" button on the crypto screen that emits `depositConfirmed`, so you can start watching for the transfer. Defaults to `false`.
</ResponseField>

<ResponseField name="initialStep" type="&#x22;amount&#x22; | &#x22;crypto&#x22; | &#x22;bank&#x22;">
  Open straight onto a rail instead of the picker. `crypto` and `bank` need no amount; their back button emits `dismissed` because there is no picker behind them. Defaults to `"amount"`.
</ResponseField>

## Events

Pass a callback in the create options (or React prop) to receive these.

### `onDepositInitiated`

The payer confirmed an amount and a rail. Fires for every rail, before any instructions render — the analytics/funnel hook.

**Signature:** `((payload: { method: "crypto" | "bank" | "card" | "platform_balance"; amount: number; currency: string; paymentMethodId?: string | undefined; }) => void)`

### `onCardDepositRequested`

A saved card was chosen. Charge it on your side, then call `showStep({ step: "amount" })` to return the element to the picker.

**Signature:** `((payload: { amount: number; currency: string; paymentMethodId: string; }) => void)`

### `onAddCardRequested`

The "Add card" row was picked — open your card-collection flow.

**Signature:** `((payload: Record<string, never>) => void)`

### `onBankSelected`

The bank rail was chosen while `deferBankToHost` is set — run your step, then show the fields yourself or call `showStep({ step: "bank" })`.

**Signature:** `((payload: Record<string, never>) => void)`

### `onPlatformBalanceSelected`

The platform-balance row was picked. It carries no amount — your own screen collects that.

**Signature:** `((payload: Record<string, never>) => void)`

### `onDepositConfirmed`

The payer said they sent the crypto. `since` is a unix-seconds floor to start matching incoming transfers from (it looks slightly back in time, so a transfer sent moments before the click still matches).

**Signature:** `((payload: { network: string; token: string; networkLabel: string; since: number; }) => void)`

### `onStepChanged`

The visible screen changed.

**Signature:** `((payload: { step: "amount" | "crypto" | "bank"; }) => void)`

### `onDismissed`

The payer backed out of a rail the element was opened directly onto — close the surface holding it.

**Signature:** `((payload: Record<string, never>) => void)`

### `onLoaderStart`

Fired the moment the element's own loading skeleton has painted inside its frame — the earliest point a consumer-managed loading state can hand off without ever exposing a blank. Always precedes `onReady`; most consumers only need `onReady`.

**Signature:** `(() => void)`

### `onReady`

Fired once the element has booted and painted its first complete frame.

**Signature:** `(() => void)`

### `onError`

Fired when the element fails to load or crashes; the element shows its own error fallback. `message` is human-readable; framework refusals also carry `code` (e.g. `HOST_SOURCE_FAILED`, with `sourceKey` naming the failed hostState key) so hosts can switch on codes, never message text.

**Signature:** `((e: { message: string; code?: string | undefined; sourceKey?: string | undefined; }) => void)`

## Methods

Call these on the element handle — the return of `create` (vanilla) or the component `ref` (React).

### `showStep`

Move the element to a screen. `{ step: "amount" }` is how you hand control back after settling a card or platform-balance deposit on your side.

**Signature:** `(input: { step: "amount" | "crypto" | "bank"; }) => Promise<void>`

### `refresh`

Re-resolve the account's funding rails. Call it after anything on your side changes what the account can offer — finishing bank onboarding, for instance — so the new rail appears without waiting for the cache to expire.

**Signature:** `() => Promise<void>`

### `mount`

Place the element on the page: appends its container to `target` (a CSS selector or an element) and starts loading. Nothing renders until this is called. React consumers never call it — the component mounts itself.

**Signature:** `(target: string | HTMLElement) => void`

### `destroy`

Remove the element from the page and release its frame and subscriptions. Safe to call more than once. React consumers never call it — unmounting the component does it.

**Signature:** `() => void`

### `update`

Change this element's consumer props after mount — it re-renders with the merged props. React consumers never call it — updating the JSX props does the same.

**Signature:** `(options: Partial<DepositElementProps>) => void`

## Styling

Each part below is a stable class name — safe to depend on. Restyle a part by mapping its class to a **style declaration object** under `appearance.classes` (properties camelCase or kebab-case, values as strings with units — the same shape as React's `style` prop). The element renders in its own frame, so page stylesheets can't reach it: these declarations are sanitized against a safe-property allowlist and injected inside the frame for you.

| Class                  | Targets                                         |
| ---------------------- | ----------------------------------------------- |
| `.whop-DepositSurface` | The deposit element root — one screen at a time |

```ts theme={null}
const wallet = whop.wallet.create({
  appearance: {
    classes: {
      'whop-DepositSurface': { borderRadius: '8px', fontWeight: '600' }
    }
  }
});

// restyle live at any point — the same shape through update()
wallet.update({
  appearance: {
    classes: { 'whop-DepositSurface': { fontWeight: '700' } }
  }
});
```

In React, pass the same object as the `appearance` prop on `<Wallet>`; `appearance` also applies globally at `WhopElements({ appearance })`.
