> ## 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.

# Components

> The full component catalog: core, card form and utility components, their hierarchy, and how they communicate.

Primer Checkout provides a set of components that work together to create a complete payment experience. This page gives you an overview of all available components and how they relate to each other.

## Component Hierarchy

> [tab] Web
>
> The components follow a hierarchical structure where parent components provide context to their children. Each parent literally contains its children. The spatial nesting mirrors the DOM nesting.
>
> > [tab] Without vault
>
> > [tab] With vault

> [tab] Android
>
> The components follow a hierarchical structure where the checkout controller manages presentation components, which in turn contain SDK UI elements.
>
> > [tab] CheckoutSheet
>
> > [tab] CheckoutHost

> [tab] iOS
>
> The iOS SDK uses a SwiftUI slot hierarchy. The managed `PrimerCheckout` view renders the full flow on its own and exposes no slots. For a composable layout, the `.primerCheckoutSession` modifier places your `PrimerCheckoutSession` in the environment. Composable views such as `PrimerCardForm` and `PrimerPaymentMethods` resolve it from there.

## Core Components

> [tab] Web
>
> | Component | Purpose |
> | - | - |
> | [`<primer-checkout>`](https://primer.io/docs/sdk/primer-checkout-web/components/primer-checkout) | Root component that initializes the SDK and provides checkout context |
> | [`<primer-main>`](https://primer.io/docs/sdk/primer-checkout-web/components/primer-main) | Manages checkout states and provides layout customization |
> | [`<primer-payment-method>`](https://primer.io/docs/sdk/primer-checkout-web/components/primer-payment-method) | Renders a specific payment method (card, PayPal, Apple Pay, etc.) |
> | [`<primer-payment-method-container>`](https://primer.io/docs/sdk/primer-checkout-web/components/primer-payment-method-container) | Container for filtering and organizing multiple payment methods |

> [tab] Android
>
> ### Checkout controllers
>
> | Function | Returns | Purpose |
> | - | - | - |
> | `rememberPrimerCheckoutController()` | `PrimerCheckoutController` | Main session controller |
> | `rememberCardFormController()` | `PrimerCardFormController` | Card form state and actions |
> | `rememberPaymentMethodsController()` | `PrimerPaymentMethodsController` | Available payment methods |
> | `rememberVaultedPaymentMethodsController()` | `PrimerVaultedPaymentMethodsController` | Saved payment methods |
>
> ### Presentation components
>
> | Component | Description | API Reference |
> | - | - | - |
> | `PrimerCheckoutSheet` | Modal bottom sheet checkout | [Reference](https://primer.io/docs/sdk/android-checkout/v3.0.0-beta/api/primer-checkout-sheet.md) |
> | `PrimerCheckoutHost` | Inline checkout host | [Reference](https://primer.io/docs/sdk/android-checkout/v3.0.0-beta/api/primer-checkout-host.md) |
> | `PrimerCardForm` | Card payment form | [Reference](https://primer.io/docs/sdk/android-checkout/v3.0.0-beta/api/card-form/primer-card-form.md) |
> | `PrimerPaymentMethods` | Payment method list | [Reference](https://primer.io/docs/sdk/android-checkout/v3.0.0-beta/api/payment-methods/primer-payment-methods.md) |

> [tab] iOS
>
> ### Entry points
>
> | Component | Description | API Reference |
> | - | - | - |
> | `PrimerCheckout` | Managed SwiftUI view that renders the full default flow | [Reference](https://primer.io/docs/sdk/ios-checkout/v3.0.0-beta/api/primer-checkout.md) |
> | `PrimerCheckoutSession` + `.primerCheckoutSession` | Session owner for inline, composable SwiftUI layouts | [Reference](https://primer.io/docs/sdk/ios-checkout/v3.0.0-beta/api/primer-checkout-session.md) |
> | `PrimerCheckoutPresenter` | UIKit presenter (modal sheet) with a delegate | [Reference](https://primer.io/docs/sdk/ios-checkout/v3.0.0-beta/api/primer-checkout-presenter.md) |
>
> ### Composable views
>
> Each composable view exposes slots and resolves its session from the environment injected by `.primerCheckoutSession(_:theme:onCompletion:)`.
>
> | Component | Description | API Reference |
> | - | - | - |
> | `PrimerCardForm` | Card payment form with `cardDetails`, `billingAddress`, and `submitButton` slots | [Reference](https://primer.io/docs/sdk/ios-checkout/v3.0.0-beta/api/card-form/primer-card-form.md) |
> | `PrimerPaymentMethods` | Available payment method list with `header`, `method`, and `emptyState` slots | [Reference](https://primer.io/docs/sdk/ios-checkout/v3.0.0-beta/api/payment-methods/primer-payment-methods.md) |
> | `PrimerVaultedPaymentMethods` | Saved payment method shortcut for returning customers, with `header`, `item`, and `submitButton` slots. It pays with the selected saved method and renders nothing when none is saved. | [Reference](https://primer.io/docs/sdk/ios-checkout/v3.0.0-beta/api/payment-methods/vaulted-payment-methods.md) |

## Card Form Components

> [tab] Web
>
> | Component | Purpose |
> | - | - |
> | [`<primer-card-form>`](https://primer.io/docs/sdk/primer-checkout-web/components/primer-card-form/primer-card-form) | Container that provides context for card inputs |
> | [`<primer-input-card-number>`](https://primer.io/docs/sdk/primer-checkout-web/components/primer-card-form/primer-input-card-number) | Secure hosted input for card number |
> | [`<primer-input-card-expiry>`](https://primer.io/docs/sdk/primer-checkout-web/components/primer-card-form/primer-input-card-expiry) | Secure hosted input for expiry date |
> | [`<primer-input-cvv>`](https://primer.io/docs/sdk/primer-checkout-web/components/primer-card-form/primer-input-cvv) | Secure hosted input for CVV |
> | [`<primer-input-card-holder-name>`](https://primer.io/docs/sdk/primer-checkout-web/components/primer-card-form/primer-input-card-holder-name) | Input for cardholder name |
> | [`<primer-card-form-submit>`](https://primer.io/docs/sdk/primer-checkout-web/components/primer-card-form/primer-card-form-submit) | Submit button with built-in loading states |
> | [`<primer-input-label>`](https://primer.io/docs/sdk/primer-checkout-web/components/primer-card-form/primer-input-label) | Label component for card inputs |
> | [`<primer-input-wrapper>`](https://primer.io/docs/sdk/primer-checkout-web/components/primer-card-form/primer-input-wrapper) | Wrapper for styling and layout of inputs |
> | [`<primer-billing-address>`](https://primer.io/docs/sdk/primer-checkout-web/components/primer-card-form/primer-billing-address) | Billing address collection form |

> [tab] Android
>
> ### Defaults objects
>
> | Object | Parent Component | Sub-components |
> | - | - | - |
> | `PrimerCheckoutSheetDefaults` | `PrimerCheckoutSheet` | `Splash`, `Loading`, `Success`, `Error`, `PaymentMethodSelection`, `VaultedMethods`, `PaymentMethods` |
> | `CardFormDefaults` | `PrimerCardForm` | `CardNumberField`, `ExpiryField`, `CvvField`, `CardholderField`, `CardNetworkField`, `CountryCodeField`, billing fields, `SubmitButton` |
> | `PaymentMethodsDefaults` | `PrimerPaymentMethods` | `SectionHeader`, `Method`, `EmptyState` |
>
> ### State types
>
> | Type | Purpose | Values |
> | - | - | - |
> | `PrimerCheckoutState` | Checkout lifecycle and payment outcomes | `Loading`, `Ready`, `Success`, `Failure` |
> | `PrimerCardFormController.State` | Card form state | Field values, validation, loading |

> [tab] iOS
>
> ### Defaults namespaces
>
> Each composable view falls back to its `Defaults` namespace when a slot is omitted. You can also call these helpers inside your own slots to keep the SDK rendering while adding custom layout.
>
> | Namespace | Parent component | Section helpers | Per-field building blocks |
> | - | - | - | - |
> | `CardFormDefaults` | `PrimerCardForm` | `cardDetails`, `billingAddress`, `submitButton` | `cardNumber`, `expiryDate`, `cvv`, `cardholderName`, `cardNetwork`, `countryCode`, `firstName`, `lastName`, `addressLine1`, `addressLine2`, `city`, `state`, `postalCode`, `phoneNumber` |
> | `PaymentMethodsDefaults` | `PrimerPaymentMethods` | `header`, `method`, `emptyState` | — |
> | `VaultedPaymentMethodsDefaults` | `PrimerVaultedPaymentMethods` | `header`, `item`, `submitButton` | — |
>
> Each `CardFormDefaults` per-field block takes the `PrimerCardFormSession` and returns a view: `CardFieldContent`, or `CardNetworkFieldContent` for `cardNetwork`. Every block except `cardNetwork` renders nothing unless its field is part of the active `CardFormConfiguration`. `cardNetwork` is a standalone co-badged card network selector. It renders only when the card has more than one available network. The `cardNumber` block and the full `cardDetails` section already show the network selector inside the card number field. Do not add `cardNetwork` next to either, or two selectors appear. Use `cardNetwork` only when you want the selector outside the card number field.
>
> ### Sessions
>
> | Session | Purpose | Key members |
> | - | - | - |
> | `PrimerCardFormSession` | Card form state and actions | `state`, `updateCardNumber(_:)`, `updateCountryCode(_:)`, `selectCardNetwork(_:)`, `submit()` |
> | `PrimerSelectionSession` | Payment method selection | `state`, `select(_:)`, `selectVaulted(_:)` (pays with a saved method), `vaultedPaymentMethods` |
>
> ### State types
>
> | Type | Purpose | Key properties |
> | - | - | - |
> | `PrimerCheckoutState` | Checkout lifecycle and outcome | `.initializing`, `.ready`, `.success`, `.failure`, `.dismissed` |
> | `PrimerCardFormState` | Card form state | `isValid`, `isLoading`, `fieldErrors`, `selectedNetwork`, `selectedCountry`, `data` |
> | `PrimerPaymentMethodSelectionState` | Payment method list | Available and selected payment methods |
>
> ### Field presence and styling
>
> There is no per-field configuration or styling struct. Which fields appear is Dashboard-driven through `CardFormConfiguration` (read from `session.state.configuration`), and visual styling is theme-driven via `PrimerCheckoutTheme` design tokens. To recompose a layout, arrange the `CardFormDefaults` per-field building blocks inside your own slot:
>
> ```swift theme={"dark"}
> PrimerCardForm(
>   cardDetails: { session in
>     VStack(spacing: 12) {
>       CardFormDefaults.cardNumber(session)
>       HStack(spacing: 12) {
>         CardFormDefaults.expiryDate(session)
>         CardFormDefaults.cvv(session)
>       }
>       CardFormDefaults.cardholderName(session)
>     }
>   }
> )
> ```

## Utility Components

> [tab] Web
>
> | Component | Purpose |
> | - | - |
> | [`<primer-error-message-container>`](https://primer.io/docs/sdk/primer-checkout-web/components/primer-error-message-container) | Displays payment error messages |
> | [`<primer-vault-manager>`](https://primer.io/docs/sdk/primer-checkout-web/components/primer-vault-manager) | Manages saved payment methods |
> | [`<primer-show-other-payments>`](https://primer.io/docs/sdk/primer-checkout-web/components/primer-show-other-payments) | Toggle button to show additional payment methods |

> [tab] Android
>
> ### Theming
>
> | Class | Purpose |
> | - | - |
> | `PrimerTheme` | Root theme container |
> | `LightColorTokens` | Light mode colors |
> | `DarkColorTokens` | Dark mode colors |
> | `SpacingTokens` | Spacing values |
> | `TypographyTokens` | Font styles |
> | `RadiusTokens` | Corner radius |
> | `WidthTokens` | Border widths |
> | `SizeTokens` | Component sizes |

> [tab] iOS
>
> ### Theming
>
> | Struct | Purpose |
> | - | - |
> | `PrimerCheckoutTheme` | Root theme container |
> | `ColorOverrides` | Brand, background, text, border, icon, focus, and loader colors. Set light mode with `colors` and dark mode with `darkColors`. A color left nil in `darkColors` uses Primer's dark default, even when `colors` sets it. |
> | `RadiusOverrides` | Corner radius values |
> | `SpacingOverrides` | Spacing values |
> | `SizeOverrides` | Component sizes |
> | `TypographyOverrides` | Font styles and sizes |
> | `WidthOverrides` | Border widths for the default, focus, error, and selected states |
>
> ### Slot closures
>
> Customization points are the slots on the composable views. Each slot receives the relevant session (or model) and returns your view. `PrimerCardForm` and `PrimerPaymentMethods` slots are `@ViewBuilder` closures. `PrimerVaultedPaymentMethods` slots return `AnyView`, so wrap your content in `AnyView(...)`.
>
> | Slot | Receives | On |
> | - | - | - |
> | `cardDetails`, `billingAddress`, `submitButton` | `PrimerCardFormSession` | `PrimerCardForm` |
> | `header`, `emptyState` | `PrimerSelectionSession` | `PrimerPaymentMethods` |
> | `method` | `CheckoutPaymentMethod`, `() -> Void` | `PrimerPaymentMethods` |
> | `header` | `PrimerSelectionSession` | `PrimerVaultedPaymentMethods` |
> | `item` | `VaultedMethod`, `Bool` (is selected), `() -> Void` (on select) | `PrimerVaultedPaymentMethods` |
> | `submitButton` | `Bool` (is loading), `Bool` (is enabled), `() -> Void` (on submit) | `PrimerVaultedPaymentMethods` |

## Basic Usage

> [tab] Web
>
> ```html theme={"dark"}
> <primer-checkout client-token="your-client-token">
>   <primer-main slot="main">
>     <div slot="payments">
>       <!-- Payment methods appear here -->
>       <primer-payment-method type="PAYMENT_CARD"></primer-payment-method>
>       <primer-payment-method type="PAYPAL"></primer-payment-method>
>
>       <!-- Error display -->
>       <primer-error-message-container></primer-error-message-container>
>     </div>
>
>     <div slot="checkout-complete">
>       <h2>Payment successful!</h2>
>     </div>
>   </primer-main>
> </primer-checkout>
> ```

> [tab] Android
>
> ```kotlin theme={"dark"}
> @Composable
> fun CheckoutScreen(clientToken: String) {
>     val checkout = rememberPrimerCheckoutController(clientToken)
>     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.primerError.description}")
>             }
>             else -> Unit
>         }
>     }
>
>     PrimerCheckoutSheet(
>         checkout = checkout,
>         onDismiss = { navigateBack() },
>     )
> }
> ```

> [tab] iOS
>
> ```swift theme={"dark"}
> struct CheckoutView: View {
>   let clientToken: String
>
>   var body: some View {
>     PrimerCheckout(
>       clientToken: clientToken,
>       primerSettings: PrimerSettings(paymentHandling: .auto),
>       primerTheme: PrimerCheckoutTheme(
>         colors: ColorOverrides(primerColorBrand: .blue)
>       ),
>       onCompletion: { state in
>         switch state {
>         case .success(let result):
>           print("Payment: \(result.paymentId)")
>         case let .failure(error, _):
>           print("Failed: \(error.errorId)")
>         case .dismissed:
>           print("Dismissed")
>         default:
>           break
>         }
>       }
>     )
>   }
> }
> ```

## How Components Communicate

Components communicate through:

1. **Context inheritance** - Child components receive context from their parents (e.g., card inputs receive form context from their parent card form)
2. **Events** - Components emit events that you can listen to for state changes
3. **Customization points** (Slots on Web, Composable lambdas on Android, slot closures on iOS) - Allow you to inject custom content at specific points

> [!NOTE]
>
> For details on events, see the [Events guide](https://primer.io/docs/checkout/primer-checkout/configuration/events.md).

## Customization at Each Level

> [tab] Web
>
> * **`<primer-checkout>`** - SDK options, theming, global configuration
> * **`<primer-main>`** - Layout structure through customization points
> * **`<primer-payment-method>`** - Payment method-specific options
> * **`<primer-card-form>`** - Complete control over card form layout and styling

> [tab] Android
>
> * **`PrimerCheckoutSheet` / `PrimerCheckoutHost`** - Presentation mode and event handling
> * **`PrimerCheckoutSheetDefaults`** - Override default screens (splash, loading, success, error)
> * **`CardFormDefaults`** - Customize individual card form fields
> * **`PrimerTheme`** - Colors, typography, spacing, and border radius

> [tab] iOS
>
> * **`PrimerCheckout`** - Client token, settings, theme, and completion handling for the managed flow
> * **`PrimerCheckoutSession` + `.primerCheckoutSession`** - Inline, composable layouts and completion handling through `onCompletion`
> * **`PrimerPaymentMethods`** - `header`, `method`, and `emptyState` slots for the payment method list
> * **`PrimerCardForm`** - `cardDetails`, `billingAddress`, and `submitButton` slots, recomposed from `CardFormDefaults`
> * **`PrimerCheckoutTheme`** - Light and dark colors, typography, spacing, sizes, radius, and border widths

## See also

> [card] [Using Slots](https://primer.io/docs/checkout/primer-checkout/build-your-ui/layout-customization.md)
>
> Learn how to customize layout with slots

> [card] [Build a custom card form](https://primer.io/docs/checkout/primer-checkout/guides-and-recipes/build-custom-card-form.md)
>
> Step-by-step tutorial for card form customization

> [card] [Styles](https://primer.io/docs/checkout/primer-checkout/build-your-ui/styling-customization.md)
>
> Customize appearance with CSS variables

> [card] [SDK Reference](https://primer.io/docs/sdk/primer-checkout-web/components/primer-checkout.md)
>
> Detailed API documentation for all components


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