Skip to main content
Primer Checkout iOS SDK is currently in beta (v3.0.0-beta.1). The API is subject to change before the stable release.
PrimerPaymentMethods is the SwiftUI view that renders the list of available payment methods. It is composed from three @ViewBuilder slots — a header, a per-method method row, and an emptyState — and resolves its PrimerSelectionSession from the environment supplied by the .primerCheckoutSession(_:) modifier. Each slot defaults to the matching helper on PaymentMethodsDefaults, so calling PrimerPaymentMethods() with no arguments renders the SDK’s built-in UI. Override any one slot to customize that part of the list while keeping the defaults for the rest.
PrimerPaymentMethods is available on iOS 15.0 and later (@available(iOS 15.0, *)).

Signature

@available(iOS 15.0, *)
public struct PrimerPaymentMethods<Header: View, Method: View, Empty: View>: View {
  public init(
    @ViewBuilder header: @escaping (PrimerSelectionSession) -> Header
      = { PaymentMethodsDefaults.header($0) },
    @ViewBuilder method: @escaping (CheckoutPaymentMethod, @escaping () -> Void) -> Method
      = { PaymentMethodsDefaults.method($0, onSelect: $1) },
    @ViewBuilder emptyState: @escaping (PrimerSelectionSession) -> Empty
      = { PaymentMethodsDefaults.emptyState($0) }
  )
}

Parameters

ParameterTypeDefaultDescription
header(PrimerSelectionSession) -> HeaderPaymentMethodsDefaults.header($0)Slot for the section header rendered above the list. Receives the PrimerSelectionSession.
method(CheckoutPaymentMethod, @escaping () -> Void) -> MethodPaymentMethodsDefaults.method($0, onSelect: $1)Slot rendered once per available method. Receives the CheckoutPaymentMethod and an onSelect closure to invoke when the row is tapped.
emptyState(PrimerSelectionSession) -> EmptyPaymentMethodsDefaults.emptyState($0)Slot shown when no payment methods are available. Receives the PrimerSelectionSession.

Default behavior

By default PrimerPaymentMethods arranges its slots in a vertical stack:
  • Renders the default header.
  • When session.state.paymentMethods is non-empty, renders one default row per method. Each row’s tap triggers session.select(paymentMethod), starting that method’s flow.
  • When session.state.paymentMethods is empty, renders the default empty state.
If no PrimerSelectionSession is present in the environment (the view is used outside .primerCheckoutSession(_:)), nothing is rendered.
import SwiftUI
import PrimerSDK

struct CheckoutScreen: View {
  @StateObject private var session = PrimerCheckoutSession(clientToken: clientToken)

  var body: some View {
    ScrollView {
      PrimerPaymentMethods()
    }
    .primerCheckoutSession(session) { state in
      handle(state)
    }
  }
}
Wire the view hierarchy with .primerCheckoutSession(_:). PrimerPaymentMethods reads its session from the environment — you do not pass the session into the view directly.

CheckoutPaymentMethod

CheckoutPaymentMethod describes a single payment method available for selection. It contains the method’s display information and optional custom styling. The method slot receives one instance per available method, and selecting a method is also surfaced through session.state.selectedPaymentMethod.
@available(iOS 15.0, *)
public struct CheckoutPaymentMethod: Equatable, Identifiable {
  public let id: String
  public let type: String
  public let name: String
  public let icon: UIImage?
  public let surcharge: Int?
  public let hasUnknownSurcharge: Bool
  public let formattedSurcharge: String?
  public let backgroundColor: UIColor?
  public let buttonText: String?
  public let textColor: UIColor?
  public let borderColor: UIColor?
  public let borderWidth: CGFloat?
  public let cornerRadius: CGFloat?
}

Properties

PropertyTypeDescription
idStringUnique identifier for this payment method instance.
typeStringThe payment method type identifier (e.g., "PAYMENT_CARD", "PAYPAL", "APPLE_PAY").
nameStringHuman-readable display name for the payment method.
iconUIImage?Icon image to display for this payment method.
surchargeInt?Surcharge amount in minor currency units (e.g., cents), if applicable.
hasUnknownSurchargeBoolIndicates whether the surcharge amount is unknown (e.g., varies by card network).
formattedSurchargeString?Pre-formatted surcharge string for display (e.g., "+ $0.50").
backgroundColorUIColor?Custom background color for the payment method button.
buttonTextString?Custom button text from display metadata (e.g., "Pay with Klarna").
textColorUIColor?Custom text color for the payment method button.
borderColorUIColor?Custom border color for the payment method button.
borderWidthCGFloat?Custom border width for the payment method button.
cornerRadiusCGFloat?Custom corner radius for the payment method button.
CheckoutPaymentMethod conforms to Identifiable via id, so you can iterate methods directly with ForEach when building a custom list.

Customization

Custom method row

Override the method slot to render your own row. The slot receives the CheckoutPaymentMethod and an onSelect closure — call onSelect when the user taps your row to start that method’s flow.
PrimerPaymentMethods(
  method: { paymentMethod, onSelect in
    Button(action: onSelect) {
      HStack {
        if let icon = paymentMethod.icon {
          Image(uiImage: icon)
            .resizable()
            .scaledToFit()
            .frame(width: 28, height: 28)
        }
        Text(paymentMethod.buttonText ?? paymentMethod.name)
        Spacer()
        if let surcharge = paymentMethod.formattedSurcharge {
          Text(surcharge)
            .foregroundColor(.secondary)
        }
      }
      .padding()
    }
    .buttonStyle(.plain)
  }
)

Custom empty state

Override the emptyState slot to control what appears when no methods are available. The slot receives the PrimerSelectionSession so you can read selection state if needed.
PrimerPaymentMethods(
  emptyState: { _ in
    VStack(spacing: 12) {
      Image(systemName: "creditcard.and.123")
        .font(.largeTitle)
      Text("No payment methods are available right now.")
        .multilineTextAlignment(.center)
        .foregroundColor(.secondary)
    }
    .frame(maxWidth: .infinity)
    .padding()
  }
)

Custom header

Override the header slot to replace the default section title.
PrimerPaymentMethods(
  header: { _ in
    Text("Choose how to pay")
      .font(.title2.weight(.semibold))
      .frame(maxWidth: .infinity, alignment: .leading)
  }
)
The generic parameters Header, Method, and Empty are inferred from the slots you provide. When overriding only some slots, the remaining slots keep their PaymentMethodsDefaults bodies — you do not need to re-specify them.

See also

PrimerSelectionSession

The observable session that drives the method list and selection.

PaymentMethodsDefaults

Default slot bodies used by PrimerPaymentMethods.

PrimerVaultedPaymentMethods

Render and select saved (vaulted) payment methods.

PrimerCardForm

The slot-based card entry composable.