Component Hierarchy
- Web
- Android
- iOS
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.
- Without vault
- With vault
The components follow a hierarchical structure where the checkout controller manages presentation components, which in turn contain SDK UI elements.
- CheckoutSheet
- CheckoutHost
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
- Web
- Android
- iOS
| Component | Purpose |
|---|---|
<primer-checkout> | Root component that initializes the SDK and provides checkout context |
<primer-main> | Manages checkout states and provides layout customization |
<primer-payment-method> | Renders a specific payment method (card, PayPal, Apple Pay, etc.) |
<primer-payment-method-container> | Container for filtering and organizing multiple payment methods |
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
Entry points
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 |
PrimerPaymentMethods | Available payment method list with header, method, and emptyState slots | Reference |
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 |
Card Form Components
- Web
- Android
- iOS
| Component | Purpose |
|---|---|
<primer-card-form> | Container that provides context for card inputs |
<primer-input-card-number> | Secure hosted input for card number |
<primer-input-card-expiry> | Secure hosted input for expiry date |
<primer-input-cvv> | Secure hosted input for CVV |
<primer-input-card-holder-name> | Input for cardholder name |
<primer-card-form-submit> | Submit button with built-in loading states |
<primer-input-label> | Label component for card inputs |
<primer-input-wrapper> | Wrapper for styling and layout of inputs |
<primer-billing-address> | Billing address collection form |
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 |
Defaults namespaces
Each composable view falls back to itsDefaults 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 | — |
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 throughCardFormConfiguration (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:PrimerCardForm(
cardDetails: { session in
VStack(spacing: 12) {
CardFormDefaults.cardNumber(session)
HStack(spacing: 12) {
CardFormDefaults.expiryDate(session)
CardFormDefaults.cvv(session)
}
CardFormDefaults.cardholderName(session)
}
}
)
Utility Components
- Web
- Android
- iOS
| Component | Purpose |
|---|---|
<primer-error-message-container> | Displays payment error messages |
<primer-vault-manager> | Manages saved payment methods |
<primer-show-other-payments> | Toggle button to show additional payment methods |
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 |
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
- Web
- Android
- iOS
<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>
@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() },
)
}
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:- Context inheritance - Child components receive context from their parents (e.g., card inputs receive form context from their parent card form)
- Events - Components emit events that you can listen to for state changes
- Customization points (Slots on Web, Composable lambdas on Android, slot closures on iOS) - Allow you to inject custom content at specific points
For details on events, see the Events guide.
Customization at Each Level
- Web
- Android
- iOS
<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
PrimerCheckoutSheet/PrimerCheckoutHost- Presentation mode and event handlingPrimerCheckoutSheetDefaults- Override default screens (splash, loading, success, error)CardFormDefaults- Customize individual card form fieldsPrimerTheme- Colors, typography, spacing, and border radius
PrimerCheckout- Client token, settings, theme, and completion handling for the managed flowPrimerCheckoutSession+.primerCheckoutSession- Inline, composable layouts and completion handling throughonCompletionPrimerPaymentMethods-header,method, andemptyStateslots for the payment method listPrimerCardForm-cardDetails,billingAddress, andsubmitButtonslots, recomposed fromCardFormDefaultsPrimerCheckoutTheme- Light and dark colors, typography, spacing, sizes, radius, and border widths
See also
Using Slots
Learn how to customize layout with slots
Build a custom card form
Step-by-step tutorial for card form customization
Styles
Customize appearance with CSS variables
SDK Reference
Detailed API documentation for all components