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

# Scopes overview

> Understand the scope hierarchy and how to access each scope

export const IOS_SCOPE_HIERARCHY = [{
  name: 'PrimerCheckout',
  note: 'SwiftUI entry point',
  children: [{
    name: 'PrimerCheckoutScope',
    stateType: 'PrimerCheckoutState',
    access: 'scope closure',
    children: [{
      name: 'PrimerPaymentMethodSelectionScope',
      stateType: 'PrimerPaymentMethodSelectionState',
      access: '.paymentMethodSelection'
    }, {
      name: 'PrimerCardFormScope',
      stateType: 'PrimerCardFormState',
      access: 'getPaymentMethodScope(.self)',
      children: [{
        name: 'PrimerSelectCountryScope',
        stateType: 'PrimerSelectCountryState',
        access: '.selectCountry'
      }]
    }, {
      name: 'PrimerApplePayScope',
      stateType: 'PrimerApplePayState',
      access: 'getPaymentMethodScope(.self)'
    }, {
      name: 'PrimerPayPalScope',
      stateType: 'PrimerPayPalState',
      access: 'getPaymentMethodScope(.self)'
    }, {
      name: 'PrimerKlarnaScope',
      stateType: 'PrimerKlarnaState',
      access: 'getPaymentMethodScope(.self)'
    }, {
      name: 'PrimerAchScope',
      stateType: 'PrimerAchState',
      access: 'getPaymentMethodScope(.self)'
    }, {
      name: 'PrimerWebRedirectScope',
      stateType: 'PrimerWebRedirectState',
      access: 'getPaymentMethodScope(.self)'
    }, {
      name: 'PrimerFormRedirectScope',
      stateType: 'PrimerFormRedirectState',
      access: 'getPaymentMethodScope(.self)'
    }, {
      name: 'PrimerQRCodeScope',
      stateType: 'PrimerQRCodeState',
      access: 'getPaymentMethodScope(.self)'
    }]
  }]
}];

export const ScopeTree = ({nodes, showLegend = true}) => {
  const renderNode = (node, depth = 0, isLast = true, prefix = '') => {
    const connector = depth === 0 ? '' : isLast ? '└──' : '├──';
    const childPrefix = prefix + (depth === 0 ? '' : isLast ? '    ' : '│   ');
    return <div key={node.name + depth} style={{
      fontFamily: 'var(--font-mono, monospace)',
      fontSize: '14px',
      lineHeight: '2'
    }}>
        <div style={{
      display: 'flex',
      alignItems: 'center',
      whiteSpace: 'nowrap',
      flexWrap: 'wrap'
    }}>
          <span style={{
      color: '#9ca3af',
      userSelect: 'none'
    }}>{prefix}{connector}</span>
          {depth > 0 && <span style={{
      width: '8px'
    }} />}
          <span style={{
      fontWeight: '500',
      color: 'var(--tw-prose-body, #374151)'
    }}>{node.name}</span>
          {node.access && <span style={{
      marginLeft: '10px',
      padding: '2px 8px',
      borderRadius: '4px',
      backgroundColor: '#f3f4f6',
      color: '#6b7280',
      fontSize: '11px',
      fontWeight: '400'
    }}>
              {node.access}
            </span>}
          {node.stateType && <span style={{
      marginLeft: '8px',
      padding: '2px 8px',
      borderRadius: '4px',
      backgroundColor: '#dbeafe',
      color: '#1d4ed8',
      fontSize: '11px',
      fontWeight: '500'
    }}>
              state: {node.stateType}
            </span>}
          {node.note && <span style={{
      marginLeft: '10px',
      color: '#9ca3af',
      fontSize: '12px',
      fontStyle: 'italic'
    }}>
              {node.note}
            </span>}
        </div>
        {node.children && node.children.map((child, i) => renderNode(child, depth + 1, i === node.children.length - 1, childPrefix))}
      </div>;
  };
  return <div style={{
    borderRadius: '8px',
    padding: '20px',
    border: '1px solid var(--tw-prose-hr, #e5e7eb)'
  }}>
      <div>
        {nodes.map((node, i) => renderNode(node, 0, i === nodes.length - 1, ''))}
      </div>
      {showLegend && <div style={{
    display: 'flex',
    alignItems: 'center',
    gap: '20px',
    paddingTop: '16px',
    marginTop: '16px',
    borderTop: '1px solid var(--tw-prose-hr, #e5e7eb)',
    fontSize: '12px',
    color: '#6b7280',
    flexWrap: 'wrap'
  }}>
          <div style={{
    display: 'flex',
    alignItems: 'center',
    gap: '6px'
  }}>
            <span style={{
    padding: '2px 8px',
    borderRadius: '4px',
    backgroundColor: '#dbeafe',
    color: '#1d4ed8',
    fontSize: '11px',
    fontWeight: '500'
  }}>
              state: Type
            </span>
            <span>Associated state type</span>
          </div>
          <div style={{
    display: 'flex',
    alignItems: 'center',
    gap: '6px'
  }}>
            <span style={{
    padding: '2px 8px',
    borderRadius: '4px',
    backgroundColor: '#f3f4f6',
    color: '#6b7280',
    fontSize: '11px'
  }}>
              .property
            </span>
            <span>How to access the scope</span>
          </div>
        </div>}
    </div>;
};

Scopes are the central building block of Primer Checkout. Each scope is a typed protocol that exposes the state, actions, and customization points for a specific part of the checkout.

## Scope hierarchy

<ScopeTree nodes={IOS_SCOPE_HIERARCHY} />

## All scopes

| Scope                               | Purpose                                                           | State type                          |
| ----------------------------------- | ----------------------------------------------------------------- | ----------------------------------- |
| `PrimerCheckoutScope`               | Top-level checkout management                                     | `PrimerCheckoutState`               |
| `PrimerPaymentMethodSelectionScope` | Payment method list and selection                                 | `PrimerPaymentMethodSelectionState` |
| `PrimerCardFormScope`               | Card form fields and validation                                   | `PrimerCardFormState`               |
| `PrimerApplePayScope`               | Apple Pay button and availability                                 | `PrimerApplePayState`               |
| `PrimerPayPalScope`                 | PayPal payment flow                                               | `PrimerPayPalState`                 |
| `PrimerKlarnaScope`                 | Klarna multi-step flow                                            | `PrimerKlarnaState`                 |
| `PrimerAchScope`                    | ACH multi-step flow                                               | `PrimerAchState`                    |
| `PrimerWebRedirectScope`            | Web redirect payment flow (e.g., Twint)                           | `PrimerWebRedirectState`            |
| `PrimerFormRedirectScope`           | Form-based redirect flow (e.g., BLIK, MBWay)                      | `PrimerFormRedirectState`           |
| `PrimerQRCodeScope`                 | QR code display and polling (e.g., PromptPay)                     | `PrimerQRCodeState`                 |
| `PrimerSelectCountryScope`          | Country picker (accessed via `PrimerCardFormScope.selectCountry`) | `PrimerSelectCountryState`          |

## Accessing scopes

### Via the scope closure

The `scope` parameter on `PrimerCheckout` provides access to the `PrimerCheckoutScope`:

```swift theme={"dark"}
PrimerCheckout(
  clientToken: clientToken,
  scope: { checkoutScope in
    // Access payment method selection directly
    let selection = checkoutScope.paymentMethodSelection

    // Access payment method scopes by type
    if let cardScope: PrimerCardFormScope = checkoutScope.getPaymentMethodScope(PrimerCardFormScope.self) {
      // Customize card form
    }
  }
)
```

### Getting payment method scopes

Use `getPaymentMethodScope` with a type parameter:

```swift theme={"dark"}
// By scope type
let cardScope: PrimerCardFormScope? = checkoutScope.getPaymentMethodScope(PrimerCardFormScope.self)

// By payment method type enum
let applePayScope: PrimerApplePayScope? = checkoutScope.getPaymentMethodScope(for: .applePay)

// By payment method type string
let paypalScope: PrimerPayPalScope? = checkoutScope.getPaymentMethodScope(for: "PAYPAL")
```

## Type aliases

Scopes use type aliases for customization closures:

| Alias                                   | Signature                                           | Used by                                             |
| --------------------------------------- | --------------------------------------------------- | --------------------------------------------------- |
| `Component`                             | `() -> any View`                                    | `splashScreen`, `loadingScreen`, `cardInputSection` |
| `ContainerComponent`                    | `(@escaping () -> any View) -> any View`            | `container`                                         |
| `ErrorComponent`                        | `(String) -> any View`                              | `errorScreen`                                       |
| `PaymentMethodItemComponent`            | `(CheckoutPaymentMethod) -> any View`               | `paymentMethodItem`                                 |
| `CountryItemComponent`                  | `(PrimerCountry, @escaping () -> Void) -> any View` | `countryItem`                                       |
| `CategoryHeaderComponent`               | `(String) -> any View`                              | `categoryHeader`                                    |
| `CardFormScreenComponent`               | `(any PrimerCardFormScope) -> any View`             | Card form `screen`                                  |
| `PaymentMethodSelectionScreenComponent` | `(PrimerPaymentMethodSelectionScope) -> any View`   | Selection `screen`                                  |
| `WebRedirectScreenComponent`            | `(any PrimerWebRedirectScope) -> any View`          | Web redirect `screen`                               |
| `WebRedirectButtonComponent`            | `(any PrimerWebRedirectScope) -> any View`          | Web redirect `payButton`                            |
| `FormRedirectScreenComponent`           | `(any PrimerFormRedirectScope) -> any View`         | Form redirect `screen`                              |
| `FormRedirectButtonComponent`           | `(any PrimerFormRedirectScope) -> any View`         | Form redirect `submitButton`                        |
| `FormRedirectFormSectionComponent`      | `(any PrimerFormRedirectScope) -> any View`         | Form redirect `formSection`                         |
| `QRCodeScreenComponent`                 | `(any PrimerQRCodeScope) -> any View`               | QR code `screen`                                    |

## Base protocol

All payment method scopes conform to `PrimerPaymentMethodScope`:

```swift theme={"dark"}
@MainActor
protocol PrimerPaymentMethodScope: AnyObject {
  associatedtype State: Equatable

  var state: AsyncStream<State> { get }
  var presentationContext: PresentationContext { get }   // default: .fromPaymentSelection
  var dismissalMechanism: [DismissalMechanism] { get }  // default: []

  func start()
  func submit()
  func cancel()
  func onBack()
  func onDismiss()
}
```

## See also

<CardGroup cols={2}>
  <Card title="State and events" icon="bolt" href="/sdk/ios-checkout/v3.0.0-beta/configuration/state-events">
    Observe state changes for each scope
  </Card>

  <Card title="Layout customization" icon="wand-magic-sparkles" href="/checkout/primer-checkout/build-your-ui/layout-customization">
    Customize UI using scope properties
  </Card>

  <Card title="PrimerCheckoutScope API" icon="book" href="/sdk/ios-checkout/v3.0.0-beta/api-reference/primer-checkout-scope">
    Full API reference
  </Card>
</CardGroup>
