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

# Configuring Checkout

> Learn how to configure Primer Checkout with component properties and SDK options

Primer Checkout uses platform-specific configuration to control checkout behavior, appearance, and payment handling.

<Tabs>
  <Tab title="Web">
    Primer Checkout Web uses two types of configuration: **component properties** (HTML attributes) and **SDK options** (JavaScript object).

    ```javascript theme={"dark"}
    const checkout = document.querySelector('primer-checkout');

    // Component properties - use setAttribute()
    checkout.setAttribute('client-token', 'your-token');

    // SDK options - assign directly
    checkout.options = {
      locale: 'en-GB',
      card: { cardholderName: { required: true } }
    };
    ```
  </Tab>

  <Tab title="Android">
    The Android SDK uses `PrimerSettings` to configure checkout behavior. Pass it when creating the checkout controller:

    ```kotlin theme={"dark"}
    val checkout = rememberPrimerCheckoutController(
        clientToken = clientToken,
        settings = PrimerSettings().apply {
            locale = Locale("fr", "FR")
            uiOptions.dismissalMechanism = listOf(DismissalMechanism.CLOSE_BUTTON)
        },
    )
    ```
  </Tab>

  <Tab title="iOS">
    The iOS SDK uses `PrimerSettings` and `PrimerCheckoutTheme` to configure checkout behavior and appearance. Pass them when creating `PrimerCheckout`:

    ```swift theme={"dark"}
    PrimerCheckout(
      clientToken: clientToken,
      primerSettings: PrimerSettings(paymentHandling: .auto),
      primerTheme: PrimerCheckoutTheme(
        colors: ColorOverrides(primerColorBrand: .blue)
      )
    )
    ```
  </Tab>
</Tabs>

***

## Configuration Overview

<Tabs>
  <Tab title="Web">
    | Type                     | How to Set                      | Examples                                           |
    | ------------------------ | ------------------------------- | -------------------------------------------------- |
    | **Component Properties** | `setAttribute()`                | `client-token`, `custom-styles`, `loader-disabled` |
    | **SDK Options**          | Direct assignment to `.options` | `locale`, `card`, `vault`, `applePay`              |

    <Warning>
      Don't mix them up. Component properties must use `setAttribute()`. SDK options must be assigned directly to `.options`.
    </Warning>
  </Tab>

  <Tab title="Android">
    | Type             | How to Set                                      | Examples                                                      |
    | ---------------- | ----------------------------------------------- | ------------------------------------------------------------- |
    | **Client token** | `rememberPrimerCheckoutController(clientToken)` | Authentication token                                          |
    | **Settings**     | `PrimerSettings` object                         | `locale`, `uiOptions`, `paymentMethodOptions`, `debugOptions` |
    | **Theme**        | `PrimerTheme` parameter on composable           | `PrimerCheckoutSheet(theme = ...)`                            |

    <Info>
      Theming is **not** part of `PrimerSettings`. Pass `PrimerTheme` directly to `PrimerCheckoutSheet` or `PrimerCheckoutHost`. See [Styling Guide](/docs/checkout/primer-checkout/build-your-ui/styling-customization).
    </Info>
  </Tab>

  <Tab title="iOS">
    | Type             | How to Set                      | Examples                                               |
    | ---------------- | ------------------------------- | ------------------------------------------------------ |
    | **Client token** | `PrimerCheckout(clientToken:)`  | Authentication token                                   |
    | **Settings**     | `PrimerSettings` parameter      | `paymentHandling`, `uiOptions`, `paymentMethodOptions` |
    | **Theme**        | `PrimerCheckoutTheme` parameter | `colors`, `radius`, `spacing`, `typography`            |

    <Info>
      Theming is **not** part of `PrimerSettings`. Pass `PrimerCheckoutTheme` as a separate parameter to `PrimerCheckout` or `PrimerCheckoutPresenter`. See [Styling Guide](/docs/checkout/primer-checkout/build-your-ui/styling-customization).
    </Info>
  </Tab>
</Tabs>

***

## Component Properties / Client Token

The client token authenticates your checkout session. Obtain this by [creating a client session](/docs/checkout/client-session).

<Tabs>
  <Tab title="Web">
    ### client-token (required)

    ```javascript theme={"dark"}
    // ✅ Correct
    checkout.setAttribute('client-token', 'your-client-token');

    // ❌ Wrong - won't work
    checkout.clientToken = 'your-token';
    ```

    ```html theme={"dark"}
    <!-- Or set directly in HTML -->
    <primer-checkout client-token="your-client-token"></primer-checkout>
    ```

    ### custom-styles

    JSON string containing CSS variables for theming.

    ```javascript theme={"dark"}
    const styles = {
      primerColorBrand: '#4a6cf7',
      primerTypographyBrand: 'Inter, sans-serif'
    };

    checkout.setAttribute('custom-styles', JSON.stringify(styles));
    ```

    > See [Styling Guide](/docs/checkout/primer-checkout/build-your-ui/styling-customization) for available properties.

    ### loader-disabled

    Disables the default loading spinner.

    ```javascript theme={"dark"}
    checkout.setAttribute('loader-disabled', 'true');
    ```
  </Tab>

  <Tab title="Android">
    Pass the client token directly when creating the checkout controller:

    ```kotlin theme={"dark"}
    val checkout = rememberPrimerCheckoutController(
        clientToken = clientToken,
    )
    ```
  </Tab>

  <Tab title="iOS">
    Pass the client token directly when creating `PrimerCheckout`:

    ```swift theme={"dark"}
    // SwiftUI
    PrimerCheckout(clientToken: clientToken)

    // UIKit
    PrimerCheckoutPresenter.presentCheckout(
      clientToken: clientToken,
      from: viewController,
      primerSettings: PrimerSettings(),
      primerTheme: PrimerCheckoutTheme()
    )
    ```
  </Tab>
</Tabs>

***

## SDK Options / Settings

<Tabs>
  <Tab title="Web">
    SDK options configure checkout behavior. Assign a JavaScript object directly to the `options` property.

    ```javascript theme={"dark"}
    // ✅ Correct - assign directly
    checkout.options = {
      locale: 'en-GB',
      card: { cardholderName: { required: true } }
    };

    // ❌ Wrong - don't use setAttribute for options
    checkout.setAttribute('options', JSON.stringify({...}));
    ```

    <Info>
      For the complete list of available options, see the [SDK Options Reference](/docs/sdk/primer-checkout-web/sdk-options-reference).
    </Info>
  </Tab>

  <Tab title="Android">
    `PrimerSettings` configures the SDK behavior for a checkout session. Pass it when creating the controller.

    ```kotlin theme={"dark"}
    val checkout = rememberPrimerCheckoutController(
        clientToken = clientToken,
        settings = PrimerSettings().apply {
            locale = Locale("fr", "FR")
            uiOptions.dismissalMechanism = listOf(DismissalMechanism.CLOSE_BUTTON)
            paymentMethodOptions.redirectScheme = "myapp"
        },
    )
    ```

    <Info>
      For the complete list of available options, see the [SDK Options Reference](/docs/sdk/android-checkout/v3.0.0-beta/api/overview).
    </Info>
  </Tab>

  <Tab title="iOS">
    `PrimerSettings` configures the SDK behavior for a checkout session. Pass it when creating `PrimerCheckout`.

    ```swift theme={"dark"}
    let settings = PrimerSettings(
      paymentHandling: .auto,
      paymentMethodOptions: PrimerPaymentMethodOptions(),
      uiOptions: PrimerUIOptions()
    )

    PrimerCheckout(
      clientToken: clientToken,
      primerSettings: settings
    )
    ```

    <Info>
      For the complete list of available options, see the [SDK Options Reference](/docs/sdk/ios-checkout/v3.0.0-beta/api/common/primer-settings).
    </Info>
  </Tab>
</Tabs>

***

## Common Patterns

<Tabs>
  <Tab title="Web">
    ### Set Locale

    ```javascript theme={"dark"}
    checkout.options = {
      locale: 'en-GB'
    };
    ```

    > [Supported locales](/docs/checkout/primer-checkout/configuration/localization)

    ### Enable Specific Payment Methods

    ```javascript theme={"dark"}
    import { PaymentMethodType } from '@primer-io/primer-js';

    checkout.options = {
      enabledPaymentMethods: [
        PaymentMethodType.PAYMENT_CARD,
        PaymentMethodType.PAYPAL,
        PaymentMethodType.ADYEN_BLIK
      ]
    };
    ```

    ### Pre-fill Cardholder Name

    ```javascript theme={"dark"}
    checkout.options = {
      card: {
        cardholderName: {
          required: true,
          visible: true,
          defaultValue: 'John Doe'
        }
      }
    };
    ```

    For runtime updates after initialization, use `primer.setCardholderName()` instead.

    ### Enable Vault (Saved Payment Methods)

    ```javascript theme={"dark"}
    checkout.options = {
      vault: {
        enabled: true
      }
    };
    ```

    ### Configure Apple Pay Button

    ```javascript theme={"dark"}
    checkout.options = {
      applePay: {
        buttonType: 'buy',
        buttonStyle: 'black'
      }
    };
    ```

    ### Configure Google Pay Button

    ```javascript theme={"dark"}
    checkout.options = {
      googlePay: {
        buttonType: 'buy',
        buttonColor: 'black',
        captureBillingAddress: true
      }
    };
    ```

    ### Configure Klarna

    ```javascript theme={"dark"}
    checkout.options = {
      klarna: {
        paymentFlow: 'DEFAULT',
        allowedPaymentCategories: ['pay_now', 'pay_later'],
        buttonOptions: {
          text: 'Pay with Klarna'
        }
      }
    };
    ```

    ### Configure Klarna via Adyen

    ```javascript theme={"dark"}
    checkout.options = {
      adyenKlarna: {
        buttonOptions: {
          text: 'Pay with Klarna'
        }
      }
    };
    ```
  </Tab>

  <Tab title="Android">
    ### Set Locale

    ```kotlin theme={"dark"}
    settings = PrimerSettings().apply {
        locale = Locale("fr", "FR")
    }
    ```

    Default is `Locale.getDefault()` (device locale). Controls SDK-internal strings and currency formatting.

    ### Custom Success/Error Screens

    Replace the default success and error screens with your own composables via slot parameters:

    ```kotlin theme={"dark"}
    PrimerCheckoutSheet(
        checkout = checkout,
        success = { checkoutData ->
            MyCustomSuccessScreen(checkoutData)
        },
        error = { error ->
            MyCustomErrorScreen(error)
        },
    )
    ```

    See [Layout Customization](/docs/checkout/primer-checkout/build-your-ui/layout-customization) for more slot examples.

    ### Configure Dismissal Behavior

    ```kotlin theme={"dark"}
    settings = PrimerSettings().apply {
        uiOptions.dismissalMechanism = listOf(DismissalMechanism.CLOSE_BUTTON)
    }
    ```

    | Value          | Behavior                   |
    | -------------- | -------------------------- |
    | `GESTURES`     | Swipe-to-dismiss (default) |
    | `CLOSE_BUTTON` | Explicit close button      |

    You can combine both: `listOf(DismissalMechanism.GESTURES, DismissalMechanism.CLOSE_BUTTON)`.

    ### Configure Google Pay

    ```kotlin theme={"dark"}
    settings = PrimerSettings().apply {
        paymentMethodOptions.googlePayOptions = PrimerGooglePayOptions(
            merchantName = "My Store",
            captureBillingAddress = true,
            emailAddressRequired = true,
            buttonStyle = GooglePayButtonStyle.BLACK,
        )
    }
    ```

    ### Set Redirect Scheme

    Required for redirect-based payment methods (PayPal, Klarna, etc.):

    ```kotlin theme={"dark"}
    settings = PrimerSettings().apply {
        paymentMethodOptions.redirectScheme = "myapp"
    }
    ```
  </Tab>

  <Tab title="iOS">
    ### Set Payment Handling

    ```swift theme={"dark"}
    let settings = PrimerSettings(paymentHandling: .auto)
    ```

    | Value     | Behavior                                           |
    | --------- | -------------------------------------------------- |
    | `.auto`   | Primer handles the full payment flow (recommended) |
    | `.manual` | Primer returns a token for server-side processing  |

    ### Toggle Managed Screens

    `PrimerCheckout` renders Primer's default init, success, and error screens. Toggle them through `uiOptions` to handle results yourself instead:

    ```swift theme={"dark"}
    let settings = PrimerSettings(
      uiOptions: PrimerUIOptions(
        isInitScreenEnabled: false,
        isSuccessScreenEnabled: false,
        isErrorScreenEnabled: false
      )
    )
    ```

    For fully custom screens, compose your own views under [`PrimerCheckoutSession`](/docs/sdk/ios-checkout/v3.0.0-beta/api/primer-checkout-session) instead of `PrimerCheckout` and drive them with the session's published state.

    ### Configure Theme Colors

    ```swift theme={"dark"}
    let theme = PrimerCheckoutTheme(
      colors: ColorOverrides(
        primerColorBrand: .blue,
        primerColorBackground: .white
      )
    )
    ```

    ### Handle Completion

    ```swift theme={"dark"}
    PrimerCheckout(
      clientToken: clientToken,
      onCompletion: { state in
        switch state {
        case .success(let result):
          print("Payment: \(result.paymentId)")
        case .failure(let error):
          print("Failed: \(error.localizedDescription)")
        case .dismissed:
          print("Dismissed")
        default:
          break
        }
      }
    )
    ```
  </Tab>
</Tabs>

***

## Complete Example

<Tabs>
  <Tab title="Web">
    ```javascript theme={"dark"}
    import { PaymentMethodType } from '@primer-io/primer-js';

    const checkout = document.querySelector('primer-checkout');

    // 1. Component properties
    checkout.setAttribute('client-token', 'your-client-token');
    checkout.setAttribute('custom-styles', JSON.stringify({
      primerColorBrand: '#4a6cf7'
    }));

    // 2. SDK options
    checkout.options = {
      locale: 'en-GB',
      enabledPaymentMethods: [
        PaymentMethodType.PAYMENT_CARD,
        PaymentMethodType.PAYPAL
      ],
      card: {
        cardholderName: {
          required: true,
          visible: true
        }
      },
      vault: {
        enabled: true
      }
    };
    ```
  </Tab>

  <Tab title="Android">
    ```kotlin theme={"dark"}
    @Composable
    fun CheckoutScreen(clientToken: String) {
        val checkout = rememberPrimerCheckoutController(
            clientToken = clientToken,
            settings = PrimerSettings().apply {
                locale = Locale("fr", "FR")
                uiOptions.dismissalMechanism = listOf(DismissalMechanism.CLOSE_BUTTON)
                paymentMethodOptions.redirectScheme = "myapp"
                paymentMethodOptions.googlePayOptions = PrimerGooglePayOptions(
                    merchantName = "My Store",
                    captureBillingAddress = true,
                )
            },
        )

        val state by checkout.state.collectAsStateWithLifecycle()

        LaunchedEffect(state) {
            when (val s = state) {
                is PrimerCheckoutState.Success -> navigateToConfirmation(s.checkoutData)
                is PrimerCheckoutState.Failure -> {
                    Log.e("Checkout", "Failed: ${s.error.description}")
                }
                else -> Unit
            }
        }

        PrimerCheckoutSheet(
            checkout = checkout,
            success = { checkoutData -> MySuccessScreen(checkoutData) },
            error = { error -> MyErrorScreen(error) },
            onDismiss = {
                navigateBack()
            },
        )
    }
    ```
  </Tab>

  <Tab title="iOS">
    ```swift theme={"dark"}
    private let primerSettings = PrimerSettings(
      paymentHandling: .auto,
      uiOptions: PrimerUIOptions(
        dismissalMechanism: [.gestures, .closeButton]
      )
    )

    private let primerTheme = PrimerCheckoutTheme(
      colors: ColorOverrides(primerColorBrand: .blue),
      radius: RadiusOverrides(primerRadiusMedium: 12)
    )

    struct CheckoutView: View {
      let clientToken: String

      var body: some View {
        PrimerCheckout(
          clientToken: clientToken,
          primerSettings: primerSettings,
          primerTheme: primerTheme,
          onCompletion: { state in
            switch state {
            case .success(let result):
              print("Payment: \(result.paymentId)")
            case .failure(let error):
              print("Failed: \(error.localizedDescription)")
            case .dismissed:
              print("Dismissed")
            default:
              break
            }
          }
        )
      }
    }
    ```
  </Tab>
</Tabs>

***

## Framework-Specific Patterns

<Tabs>
  <Tab title="Web">
    <Tabs>
      <Tab title="Vanilla JS">
        ```javascript theme={"dark"}
        document.addEventListener('DOMContentLoaded', () => {
          const checkout = document.querySelector('primer-checkout');
          checkout.setAttribute('client-token', 'your-token');
          checkout.options = { locale: 'en-GB' };
        });
        ```
      </Tab>

      <Tab title="React">
        ```tsx theme={"dark"}
        const SDK_OPTIONS = { locale: 'en-GB' };

        function CheckoutPage() {
          return (
            <primer-checkout
              client-token="your-token"
              options={SDK_OPTIONS}
            />
          );
        }
        ```

        > See [React Integration Guide](/docs/checkout/primer-checkout/frameworks/react-integration-guide) for stable references and React 18/19 differences.
      </Tab>

      <Tab title="Next.js / SSR">
        ```tsx theme={"dark"}
        'use client';

        import { useEffect } from 'react';
        import { loadPrimer } from '@primer-io/primer-js';

        const SDK_OPTIONS = { locale: 'en-GB' };

        export default function CheckoutPage() {
          useEffect(() => {
            loadPrimer();
          }, []);

          return (
            <primer-checkout
              client-token="your-token"
              options={SDK_OPTIONS}
            />
          );
        }
        ```

        > See [SSR Guide](/docs/checkout/primer-checkout/frameworks/ssr-guide) for framework-specific patterns.
      </Tab>
    </Tabs>
  </Tab>

  <Tab title="Android">
    The Android SDK uses standard Jetpack Compose patterns. Configuration is passed when creating the checkout controller:

    ```kotlin theme={"dark"}
    @Composable
    fun CheckoutScreen(clientToken: String) {
        val checkout = rememberPrimerCheckoutController(
            clientToken = clientToken,
            settings = PrimerSettings().apply {
                paymentMethodOptions.redirectScheme = "myapp"
            },
        )

        PrimerCheckoutSheet(checkout = checkout)
    }
    ```

    See the [Best Practices](/docs/checkout/primer-checkout/configuration/best-practices) guide for Compose-specific patterns.
  </Tab>

  <Tab title="iOS">
    <Tabs>
      <Tab title="SwiftUI">
        ```swift theme={"dark"}
        struct CheckoutView: View {
          let clientToken: String

          var body: some View {
            PrimerCheckout(
              clientToken: clientToken,
              primerSettings: PrimerSettings(paymentHandling: .auto),
              onCompletion: { state in
                // Handle result
              }
            )
          }
        }
        ```

        > See the [Best Practices](/docs/checkout/primer-checkout/configuration/best-practices) guide for SwiftUI-specific patterns.
      </Tab>

      <Tab title="UIKit">
        ```swift theme={"dark"}
        class CheckoutViewController: UIViewController, PrimerCheckoutPresenterDelegate {
          func showCheckout() {
            PrimerCheckoutPresenter.shared.delegate = self

            PrimerCheckoutPresenter.presentCheckout(
              clientToken: clientToken,
              from: self,
              primerSettings: PrimerSettings(paymentHandling: .auto),
              primerTheme: PrimerCheckoutTheme()
            )
          }

          func primerCheckoutPresenterDidCompleteWithSuccess(_ result: PaymentResult) {
            // Navigate to confirmation
          }

          func primerCheckoutPresenterDidFailWithError(_ error: PrimerError) {
            print("Failed: \(error.errorDescription)")
          }

          func primerCheckoutPresenterDidDismiss() {
            print("Dismissed")
          }
        }
        ```

        > See [UIKit Integration Guide](/docs/sdk/ios-checkout/v3.0.0-beta/guides/uikit-integration) for more details.
      </Tab>
    </Tabs>
  </Tab>
</Tabs>

***

## Advanced Configuration

<Tabs>
  <Tab title="Web">
    <Accordion title="Headless Vault">
      Build custom vault UIs while retaining full vault functionality. Enable headless mode:

      ```javascript theme={"dark"}
      checkout.options = {
        vault: {
          enabled: true,
          headless: true
        }
      };
      ```

      Then use `onVaultedMethodsUpdate`, `vault.createCvvInput()`, and `vault.startPayment()` to build your custom UI.

      > [Headless Vault Implementation Guide](/docs/sdk/primer-checkout-web/components/primer-vault-manager#headless-vault-implementation)
    </Accordion>

    <Accordion title="External Submit Button">
      Use your own submit button instead of the built-in one:

      ```javascript theme={"dark"}
      checkout.options = {
        submitButton: {
          useBuiltInButton: false
        }
      };

      // Trigger submission from your button
      document.getElementById('my-button').addEventListener('click', () => {
        document.dispatchEvent(new CustomEvent('primer:card-submit', {
          bubbles: true,
          composed: true
        }));
      });
      ```

      > [External Submit Button Recipe](/docs/checkout/primer-checkout/guides-and-recipes/external-submit-button)
    </Accordion>

    <Accordion title="Show Amount on Button">
      Display the payment amount on the submit button:

      ```javascript theme={"dark"}
      checkout.options = {
        submitButton: {
          amountVisible: true
        }
      };
      ```
    </Accordion>
  </Tab>

  <Tab title="Android">
    <Accordion title="Custom Submit Button">
      Override the submit button slot in `PrimerCardForm`:

      ```kotlin theme={"dark"}
      PrimerCardForm(
          controller = cardFormController,
          submitButton = {
              Button(
                  onClick = { cardFormController.submit() },
                  enabled = formState.isFormValid && !formState.isLoading,
              ) {
                  Text("Pay")
              }
          },
      )
      ```

      > [External Submit Button Recipe](/docs/checkout/primer-checkout/guides-and-recipes/external-submit-button)
    </Accordion>

    <Accordion title="Google Pay with Shipping">
      Configure Google Pay to collect billing address, email, and shipping:

      ```kotlin theme={"dark"}
      settings = PrimerSettings().apply {
          paymentMethodOptions.googlePayOptions = PrimerGooglePayOptions(
              merchantName = "My Store",
              captureBillingAddress = true,
              emailAddressRequired = true,
              shippingAddressParameters = PrimerGoogleShippingAddressParameters(
                  phoneNumberRequired = true,
              ),
              requireShippingMethod = true,
          )
      }
      ```
    </Accordion>

    <Accordion title="Stripe ACH Mandate">
      Configure mandate data for Stripe ACH payments:

      ```kotlin theme={"dark"}
      settings = PrimerSettings().apply {
          paymentMethodOptions.stripeOptions = PrimerStripeOptions(
              mandateData = MandateData.TemplateMandateData(merchantName = "My Store"),
          )
      }
      ```
    </Accordion>

    <Accordion title="3DS Configuration">
      Set the 3DS App Requestor URL:

      ```kotlin theme={"dark"}
      settings = PrimerSettings().apply {
          paymentMethodOptions.threeDsOptions = PrimerThreeDsOptions(
              threeDsAppRequestorUrl = "https://mystore.com",
          )
      }
      ```
    </Accordion>
  </Tab>

  <Tab title="iOS">
    <Accordion title="Inline Custom Layout">
      `PrimerCheckout` renders the SDK's default screens. For a fully custom layout, hold a [`PrimerCheckoutSession`](/docs/sdk/ios-checkout/v3.0.0-beta/api/primer-checkout-session) as a `@StateObject`, compose the SwiftUI views you need, and wire them up with the `.primerCheckoutSession(_:onCompletion:)` modifier:

      ```swift theme={"dark"}
      struct CustomCheckoutView: View {
        @StateObject private var session: PrimerCheckoutSession

        init(clientToken: String) {
          _session = StateObject(wrappedValue: PrimerCheckoutSession(clientToken: clientToken))
        }

        var body: some View {
          ScrollView {
            VStack(spacing: 24) {
              Text("Secure Checkout").font(.headline)
              PrimerPaymentMethods()
              PrimerCardForm()
            }
            .padding()
          }
          .primerCheckoutSession(session) { state in
            // React to the terminal PrimerCheckoutState.
          }
        }
      }
      ```
    </Accordion>

    <Accordion title="Custom Card Form Submit Button">
      Override the `submitButton` slot on [`PrimerCardForm`](/docs/sdk/ios-checkout/v3.0.0-beta/api/card-form/primer-card-form). Each slot closure receives the active [`PrimerCardFormSession`](/docs/sdk/ios-checkout/v3.0.0-beta/api/card-form/card-form-session), so you read `session.state` and call `session.submit()`:

      ```swift theme={"dark"}
      PrimerCardForm(submitButton: { session in
        Button("Pay Now") {
          session.submit()
        }
        .disabled(!session.state.isValid || session.state.isLoading)
      })
      ```

      The other slots (`cardDetails`, `billingAddress`) keep their `CardFormDefaults` styling. Place `PrimerCardForm` under the `.primerCheckoutSession` modifier so it resolves its session from the environment.

      > [Custom Submit Button Recipe](/docs/checkout/primer-checkout/guides-and-recipes/external-submit-button)
    </Accordion>
  </Tab>
</Tabs>

***

## See also

<CardGroup cols={2}>
  <Card title="Web SDK Options Reference" icon="list" href="/docs/sdk/primer-checkout-web/sdk-options-reference">
    Complete list of all available Web options
  </Card>

  <Card title="Android SDK Reference" icon="android" href="/docs/sdk/android-checkout/v3.0.0-beta/api/overview">
    Android SDK API documentation
  </Card>

  <Card title="Events Guide" icon="bolt" href="/docs/checkout/primer-checkout/configuration/events">
    Handle payment success, failure, and state changes
  </Card>

  <Card title="Styling" icon="palette" href="/docs/checkout/primer-checkout/build-your-ui/styling-customization">
    Customize colors, fonts, and spacing
  </Card>
</CardGroup>
