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

# onExit

> Fires when the shopper dismisses a launched wallet sheet or bank-linking modal.

`onExit` fires when the shopper leaves a launched surface without completing it: the wallet sheet is dismissed without authorizing, or the bank-linking modal is closed. It is the dedicated channel for "shopper dismissed something", distinct from an error.

Emitted by `applePay`, `googlePay`, `bank` (address-lookup mode), and `checkout` (when its active sub-method is one of those). Every other element omits the key from its event map; subscribing is a TypeScript error and a runtime no-op (with a console warning).

## `onExit` is not an error

`onError` is reserved for genuine failures (validation, tokenization, network, vendor errors). Shopper abandonment fires `onExit` only. Wallets and bank deliberately suppress the corresponding `onError` envelope when the underlying provider reports a cancellation or exit.

## Payload

Wallets:

```typescript theme={null}
type WalletExitPayload = { elementType: 'applePay' | 'googlePay' };
```

Bank (address-lookup mode):

```typescript theme={null}
type BankExitPayload = {
  elementType: 'bank';
  bankMode: 'address-lookup';
  linkMetadata: LinkOnExitMetadata; // always populated
  linkError?: LinkError;             // populated when the shopper exited after an in-flow error
};
```

Checkout:

```typescript theme={null}
type CheckoutExitPayload =
  | { elementType: 'checkout'; paymentMethod: 'applePay' | 'googlePay' }
  | { elementType: 'checkout'; paymentMethod: 'bank'; bankMode: 'address-lookup';
      linkMetadata: LinkOnExitMetadata; linkError?: LinkError };
```

## Example (wallet)

```javascript theme={null}
applePay.on('onExit', () => {
  showPaymentMethodPicker();
});
```

## Example (bank)

`linkMetadata` is always populated when the shopper leaves the linking modal. `linkError` is populated only when they exited after hitting an in-flow error (for example, an invalid-credentials attempt):

```javascript theme={null}
bank.on('onExit', (event) => {
  if (event.bankMode === 'address-lookup') {
    if (event.linkError) {
      analytics.track('bank_exit_with_error', {
        institution: event.linkMetadata.institution?.name,
      });
    } else {
      analytics.track('bank_modal_dismissed', {
        institution: event.linkMetadata.institution?.name,
      });
    }
  }
});
```

When `linkError` is present, the SDK additionally fires `onError` with `code: 'plaid_link_failed'` (deduplicated so consumers do not see multiple envelopes for the same underlying failure). Subscribing only to `onExit` still gives you the full context via `linkError`.

## Example (Checkout)

```javascript theme={null}
checkout.on('onExit', (event) => {
  if (event.paymentMethod === 'bank') {
    // event.bankMode is 'address-lookup', event.linkMetadata is available.
    analytics.track('bank_modal_dismissed_in_checkout');
  } else {
    // event.paymentMethod is 'applePay' or 'googlePay'.
    analytics.track('wallet_sheet_dismissed', { method: event.paymentMethod });
  }
});
```

## Naming rationale

`onExit` describes leaving a launched experience, not cancelling an in-flight operation. The shopper backs out of a sheet they themselves opened; there is no transaction to cancel. `onCancel` is intentionally reserved for any future "abort an in-progress action" semantic.

## Elements that do not emit `onExit`

`card`, standalone inputs (`email`, `phone`, `fullName`, address elements, custom elements), and `submitButton` never fire `onExit`. Their event maps omit the key.

## See also

* [`onError`](/payment-elements/events/on-error)
* [`onClick`](/payment-elements/events/on-click)
* [Wallets guide](/payment-elements/guides/wallets)
