Skip to content

Button component

Learn about how to configure the PayPal payment button component for iOS.

Basic usage

Minimal configuration

At minimum, the PayPal button component requires the following configuration to function:

let config = PayPalButtonComponentConfig()
config.fundingSource = .paypal
PropertyDescription
fundingSource
PayPalFundingSource
The payment method to support. Defaults to .paypal.

Possible values:
  • .paypal: Standard PayPal payments
  • .paylater: PayPal Pay Later financing

Advanced configuration

For more complex implementations, you can configure additional settings and features:

let config = PayPalButtonComponentConfig()

// Payment details
config.fundingSource = .paypal
config.payeeEmailAddress = "merchant@example.com"
config.paymentDescription = "Premium subscription"
config.shippingPreference = .noShipping
config.userAction = .payNow
config.locale = "en_US"

// Shipping configuration
config.shippingOptions = [
    PayPalShippingOption(
        id: "standard",
        label: "Standard Shipping",
        selected: true,
        amounts: PayPalShippingAmounts(
            currencyCode: "USD",
            shipping: "5.99"
        ),
        type: .shipping
    )
]

// Button appearance
config.style = PayPalButtonStyleConfig(
    color: .blue,
    label: .checkout,
    size: .collapsed,
    edges: .softEdges,
    contentInsets: .uniform(8)
)

// Custom content (optional)
config.customContent = {
    AnyView(
        Text("Pay with PayPal")
            .padding()
            .background(Color.blue)
            .foregroundColor(.white)
            .cornerRadius(8)
    )
}
PropertyDescription
payeeEmailAddress
String?
Your merchant email address. Defaults to nil.
paymentDescription
String?
A description of the payment shown to the buyer. Defaults to nil.
shippingPreference
PayPalShippingPreference?
The shipping details to use. Defaults to nil.

Possible values:
  • .noShipping: No shipping address required
  • .getFromFile: Get the shipping address from the PayPal account
  • .setProvidedAddress: Use the provided shipping address
userAction
PayPalUserAction?
The next step in the payment flow. Defaults to nil.

Possible values:
  • .payNow: Immediate payment capture
  • .continueAction: Continue to PayPal for payment
locale
String?
The language and region for PayPal interface (e.g., "en_US", "fr_FR"). Defaults to nil.
fundingSource
PayPalFundingSource
The payment method to support. Defaults to .paypal.

Possible values:
  • .paypal: Standard PayPal payments
  • .paylater: PayPal Pay Later financing
shippingOptions
[PayPalShippingOption]?
Details about the shipping options. Provide this when shippingPreference is .getFromFile. Defaults to nil.
style
PayPalButtonStyleConfig
Styling options for the PayPal button. Defaults to .default.
customContent
(() -> AnyView)?
Optional custom SwiftUI content to replace the default PayPal button. Defaults to nil.
paypalConsentComponent
PayPalConsentComponent?
PayPal consent component for vaulting. Defaults to nil. See Consent component.

You can find PayPal's official rules around button styling in their iOS SDK reference.

Styling

Default styling

The PayPal button component renders with these default styles:

style = PayPalButtonStyleConfig(
    color: .gold,
    label: nil,
    size: .collapsed,
    edges: .softEdges,
    contentInsets: nil
)

Custom styling

You can override the default appearance by providing custom styles:

let config = PayPalButtonComponentConfig()
config.style = PayPalButtonStyleConfig(
    color: .blue,
    label: .buyNow,
    size: .expanded,
    edges: .rounded,
    contentInsets: .custom(top: 12, leading: 16, bottom: 12, trailing: 16)
)
PropertyDescription
style
PayPalButtonStyleConfig
Styling options for the PayPal button appearance.
style.color
PayPalButtonColor
The colour of the PayPal button. Defaults to .gold.

Possible values:
  • .gold
  • .blue
  • .silver
  • .white
  • .black
  • .darkBlue
style.label
PayPalButtonLabel?
The label text of the PayPal button. Defaults to nil.

Possible values:
  • .checkout
  • .buyNow
  • .payWith
  • .payLater
style.size
PayPalButtonSize
The size of the PayPal button. Defaults to .collapsed.

Possible values:
  • .mini
  • .collapsed
  • .expanded
  • .full
style.edges
PayPalButtonEdges
The corner style of the PayPal button. Defaults to .softEdges.

Possible values:
  • .hardEdges: Square corners
  • .softEdges: Slightly rounded
  • .rounded: More rounded
  • .custom: Custom edge configuration
style.contentInsets
NSDirectionalEdgeInsets?
The padding around the button content. Defaults to nil.

Event handling

The PayPal button component provides event handlers to manage the complete payment flow:

let config = PayPalButtonComponentConfig()
config.onClick = { }
config.onApprove = { approvalData in }
config.onError = { error in }
config.onCancel = { error in }
config.onOrderCreated = { submitResult in }
config.onSubmitError = { error in }
config.onPreAuthorisation = { PayPalTransactionInitData? }
config.onGetConsent = { Bool }
CallbackDescription
onClick: (() -> Void)?Event handler for when the PayPal button is clicked. Called before payment flow starts.
onApprove: ((PayPalApprovalData) -> Void)?Event handler for when the buyer approves the transaction. Receives order and payer information.
onError: ((BaseSdkException) -> Void)?Event handler for when an error prevents checkout from proceeding.
onCancel: ((BaseSdkException) -> Void)?Event handler for when the buyer cancels the payment flow.
onOrderCreated: ((BaseSubmitResult) -> Void)?Event handler for when the PayPal order is successfully created. Contains transaction IDs.
onSubmitError: ((BaseSdkException) -> Void)?Event handler for when error occurs during order creation or submission.
onPreAuthorisation: (() async -> PayPalTransactionInitData?)?Event handler called before authorisation to provide additional transaction data like 3DS.
onGetConsent: (() -> Bool)?Event handler to get user consent status for vaulting. Return true if user consents, false otherwise.

For detailed information about event data structures and usage patterns, see Events.

Methods

The PayPal button component provides methods for lifecycle management.

buildContent()

Renders the PayPal button in SwiftUI:

struct PaymentView: View {
    @State private var paypalComponent: BaseComponent?
    
    var body: some View {
        VStack {
            if let component = paypalComponent {
                component.buildContent()
                    .frame(height: 50)
            }
        }
        .onAppear {
            createPayPalComponent()
        }
    }
}

getValue()

Note: The PayPal button component does not have a getValue() method. Payment data is provided through the onApprove callback.

For linked consent components:

let hasConsent = consentComponent.getValue() as? Bool ?? false

Examples

Basic payment button

A straightforward implementation with essential configuration and error handling:

let config = PayPalButtonComponentConfig()

// Basic settings
config.fundingSource = .paypal
config.payeeEmailAddress = "merchant@example.com"
config.paymentDescription = "Order payment"

// Essential event handlers
config.onClick = {
    print("PayPal button clicked")
}

config.onApprove = { approvalData in
    print("Payment successful - Order ID: \(approvalData.orderID)")
    // Navigate to success screen
    navigateToSuccessScreen(approvalData.orderID)
}

config.onError = { error in
    print("Payment failed: \(error.errorMessage)")
    // Show error message
    showErrorMessage("Payment failed. Please try again.")
}

config.onCancel = { error in
    print("Payment cancelled")
    // Show cancellation message
    showMessage("Payment was cancelled.")
}

Enterprise payment with full features

A comprehensive implementation with custom styling and complete event handling:

let config = PayPalButtonComponentConfig()

// Payment details
config.fundingSource = .paypal
config.payeeEmailAddress = "enterprise@example.com"
config.paymentDescription = "Enterprise subscription"
config.shippingPreference = .getFromFile
config.userAction = .continueAction
config.locale = "en_US"

// Shipping configuration
config.shippingOptions = [
    PayPalShippingOption(
        id: "standard",
        label: "Standard Shipping",
        selected: true,
        amounts: PayPalShippingAmounts(
            currencyCode: "USD",
            shipping: "5.99"
        ),
        type: .shipping
    ),
    PayPalShippingOption(
        id: "express",
        label: "Express Shipping",
        selected: false,
        amounts: PayPalShippingAmounts(
            currencyCode: "USD",
            shipping: "12.99"
        ),
        type: .shipping
    )
]

// Custom styling
config.style = PayPalButtonStyleConfig(
    color: .blue,
    label: .buyNow,
    size: .expanded,
    edges: .rounded,
    contentInsets: .custom(top: 12, leading: 16, bottom: 12, trailing: 16)
)

// Pre-authorisation with transaction data
config.onPreAuthorisation = {
    return PayPalTransactionInitData(
        addressVerification: AddressVerification(
            countryCode: "US",
            houseNumberOrName: "123",
            postalCode: "12345"
        ),
        riskScreeningData: RiskScreeningData(
            performRiskScreening: true,
            excludeDeviceData: false,
            deviceSessionId: "device-session-\(UUID().uuidString)",
            items: [
                RiskScreeningItem(
                    price: 25.00,
                    quantity: 1,
                    category: "electronics",
                    sku: "PROD-001"
                )
            ]
        )
    )
}

// Complete event handling
config.onClick = {
    print("PayPal button clicked")
    trackAnalyticsEvent("paypal_button_clicked")
}

config.onOrderCreated = { submitResult in
    print("Order created:")
    if let merchantResult = submitResult as? MerchantSubmitResult {
        print("- Merchant TX ID: \(merchantResult.merchantTransactionId)")
        print("- System TX ID: \(merchantResult.systemTransactionId)")
        trackAnalyticsEvent("paypal_order_created", params: [
            "orderId": merchantResult.systemTransactionId
        ])
    }
}

config.onApprove = { approvalData in
    print("Payment approved:")
    print("- Order ID: \(approvalData.orderID)")
    print("- Payer ID: \(approvalData.payerID)")
    
    trackAnalyticsEvent("paypal_payment_success", params: [
        "orderId": approvalData.orderID
    ])
    
    showPaymentSuccessMessage()
    DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
        navigateToSuccessScreen(approvalData.orderID)
    }
}

config.onError = { error in
    let errorMessage: String
    switch error.errorCode {
    case "SDK_ERROR":
        errorMessage = "Failed to load PayPal. Please check your connection."
    case "TRANSACTION_ERROR":
        errorMessage = "Payment processing error. Please try again."
    default:
        errorMessage = "Payment error occurred: \(error.errorMessage)"
    }
    
    print("Payment error: \(error.errorMessage)")
    trackAnalyticsEvent("paypal_payment_error", params: [
        "error": error.errorCode
    ])
    showErrorDialog(errorMessage)
}

config.onCancel = { error in
    print("Payment cancelled")
    trackAnalyticsEvent("paypal_payment_cancelled")
    showMessage("Payment was cancelled.")
}

config.onSubmitError = { error in
    print("Submit error: \(error.errorMessage)")
    showErrorDialog("Unable to process payment: \(error.errorMessage)")
}

Payment with custom button design

Implementation with custom SwiftUI content instead of the default PayPal button:

let config = PayPalButtonComponentConfig()
config.fundingSource = .paypal

// Custom content that replaces default PayPal button
config.customContent = {
    AnyView(
        HStack {
            Image(systemName: "creditcard.fill")
                .foregroundColor(.white)
            Text("Pay with PayPal")
                .font(.headline)
                .foregroundColor(.white)
        }
        .padding()
        .frame(maxWidth: .infinity)
        .background(Color.blue)
        .cornerRadius(12)
    )
}

// Configure callbacks
config.onApprove = { approvalData in
    print("Payment successful: \(approvalData.orderID)")
    handlePaymentSuccess(approvalData)
}

config.onError = { error in
    print("Payment failed: \(error.errorMessage)")
    handlePaymentError(error)
}

Payment with vaulting

Implementation with consent component for saving PayPal accounts:

// Create consent component first
let consentConfig = PayPalConsentComponentConfig(
    label: "Save my PayPal account for future transactions",
    checked: false
)
let consentComponent = try pxpCheckout.create(
    .paypalConsent,
    componentConfig: consentConfig
)

// Create PayPal button with linked consent
let paypalConfig = PayPalButtonComponentConfig()
paypalConfig.fundingSource = .paypal
paypalConfig.paypalConsentComponent = consentComponent as? PayPalConsentComponent

// Alternative: Use onGetConsent callback
paypalConfig.onGetConsent = {
    let hasConsent = UserDefaults.standard.bool(forKey: "paypal_consent")
    return hasConsent
}

paypalConfig.onApprove = { approvalData in
    print("Payment approved with consent")
    // Check consent status and handle accordingly
    handlePaymentWithVaulting(approvalData)
}