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

# showView

> Invoked when the SDK has a view to present (form or action).

`showView` is invoked when the SDK has a view ready to be presented. Either a form to collect input from the user, or an action view such as a QR code. Override this controller to embed the view in your own layout instead of letting the SDK present it full-screen.

<Note>
  WebViews: for example, 3DS challenges or redirects required by some payment methods, are always presented by the SDK full-screen. They do not come through `showView`, so overriding it does not change that behavior.
</Note>

`showView` is available on iOS and Android. On Web the SDK renders the form inside the element you pass as `elementSelector`, so there is no view to hand over. To submit that form from your own button, see [Web: submit from your own button](#web-submit-from-your-own-button).

## Behavior

If you do not override this controller, the SDK presents the view full-screen with its own header and submit button.

When you override it, the SDK delivers the view to your handler along with a `TransactionProcess` control object. You place the view wherever you want in your layout, and you call `process.onSubmit()` to tell the SDK the user has triggered submission.

You are responsible for removing the view from your layout once the transaction has moved past that step.

The controller can be invoked more than once per transaction. The `step` parameter indicates which step the view belongs to. For example, `FORM` for the data-capture form and `ACTION` for an action view such as a QR code. Use it to differentiate how you embed each view if needed.

On iOS, `FORM` carries the payment or enrollment form, and `ACTION` carries the screens the SDK renders for a method after the form: payment instructions such as a QR or a payment code, and OTP entry. `view` is `nil` when the SDK could not build an `ACTION` screen; there is nothing to embed in that case, and the transaction reports its outcome through `onStatus`.

To hand a step back to the SDK from your override, call `SdkPayments.defaultShowView(view:process:step:)`. For example, embed the form and let the SDK present the action views:

```swift theme={"theme":{"light":"github-dark","dark":"github-dark-dimmed"}}
func showView(view: AnyView?, process: SdkPayments.TransactionProcess, step: SdkPayments.TransactionViewStep) {
    guard step == .FORM, let view else {
        SdkPayments.defaultShowView(view: view, process: process, step: step)
        return
    }
    // Place `view` in your layout and call process.onSubmit() from your own button.
}
```

## Signature

<Tabs>
  <Tab title="iOS">
    ```swift theme={"theme":{"light":"github-dark","dark":"github-dark-dimmed"}}
    func showView(view: AnyView?, process: SdkPayments.TransactionProcess, step: SdkPayments.TransactionViewStep)
    ```
  </Tab>

  <Tab title="Android">
    ```kotlin theme={"theme":{"light":"github-dark","dark":"github-dark-dimmed"}}
    fun showView(view: Fragment, process: TransactionProcess, step: TransactionViewStep)
    ```
  </Tab>
</Tabs>

## TransactionProcess

`TransactionProcess` is the control object the SDK passes alongside the view. It exposes a single method:

```
onSubmit()
```

Call `process.onSubmit()` when the user triggers submission from your own UI (for example, when they tap your custom submit button). The SDK validates the form and, if valid, continues the transaction.

You don't need to handle success or failure here. The result of submission flows through [`createPayment`](/docs/yuno-sdk/controllers/create-payment) (if overridden) and [`onStatus`](/docs/yuno-sdk/controllers/on-status).

## TransactionViewStep

`TransactionViewStep` indicates which step the view corresponds to.

| Value | Meaning |
| - | - |
| `FORM` | Data-capture form (card form, APM data, etc.). |
| `ACTION` | Additional action view, such as a QR code. |

## Threading

On iOS and Android, `showView` is invoked on the main thread. You can update UI directly from inside this handler.

## Web: submit from your own button

On Web, hide the SDK's Pay button with [`showPayButton: false`](/docs/yuno-sdk/reference/objects-you-pass#showpaybutton-web-only) and call `transaction.submit()` from your own button. It is the Web counterpart of `process.onSubmit()`.

```javascript theme={"theme":{"light":"github-dark","dark":"github-dark-dimmed"}}
const transaction = sdkPayments.transaction({
    checkoutSession,
    countryCode: 'CO',
    elementSelector: '#payment-form',
    showPayButton: false,
    onStatus: (result) => {
        if (result.message?.code === 'FORM_INVALID') {
            // Not final: the form stays mounted with its field errors. The user can try again.
            return
        }
        // Final status of the transaction.
    },
})

await transaction.start({ paymentMethod: { type: 'CARD' } })

document.querySelector('#my-pay-button').addEventListener('click', () => {
    transaction.submit()
})
```

`submit()` validates the form and, if valid, continues the transaction. If the form is not valid, `onStatus` receives `INTERNAL_ERROR` with code `FORM_INVALID`. That status is not final: the form stays mounted. The result of a valid submission flows through [`createPayment`](/docs/yuno-sdk/controllers/create-payment) (if overridden) and [`onStatus`](/docs/yuno-sdk/controllers/on-status), the same as when the user clicks the SDK's Pay button.

| When you call `submit()` | What happens |
| - | - |
| The form is valid | The form is submitted. |
| The form is invalid | The form shows its field errors and `onStatus` receives `INTERNAL_ERROR` with code `FORM_INVALID`. The user can correct the form and you can call `submit()` again. |
| A payment is already in progress | Nothing. The call is ignored, so a double click does not create a second payment. |
| The form has not finished loading | `onStatus` receives `INTERNAL_ERROR` with code `FORM_INVALID`, the same as an invalid form. The user can press your button again. |
| Before `start()` is called, or after `unmount()` | It throws. Call `start()` first. |
| The form `start()` mounted is no longer on the page, because the SDK replaced it with its error screen or unmounted it | It throws. Call `start({ paymentMethod })` again to mount a new form. |
| The payment on this checkout session already finished | It throws. Create a new checkout session and a new transaction to pay again. |
| After a headless `start()` (one that passes `data`) | It throws. A headless `start()` mounts no form. |
| The payment method is a wallet | It throws. The user pays by tapping the wallet button. |
| The SDK's [payment methods list](/docs/yuno-sdk/features/payment-methods-list) is mounted and `start()` has not mounted a form | It throws. On the list, your button calls `transaction.start({ paymentMethod })` with the selected method. |
| The transaction is an enrollment | It throws. `submit()` is available for payment transactions only. |

## Related

* [Transactions](/docs/basic-concepts/transactions). How a payment flows through Yuno.
* [`createPayment`](/docs/yuno-sdk/controllers/create-payment). Receives the token after submission.
* [`onStatus`](/docs/yuno-sdk/controllers/on-status). Receives the final status.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.