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

# PrimerCardFormScope

> API reference for the card form scope protocol

`PrimerCardFormScope` provides complete control over the card payment form — fields, validation, state, and layout.

## Declaration

```swift theme={"dark"}
@MainActor
public protocol PrimerCardFormScope: PrimerPaymentMethodScope where State == PrimerCardFormState
```

## Properties

### State and context

| Property              | Type                               | Description                                                        |
| --------------------- | ---------------------------------- | ------------------------------------------------------------------ |
| `state`               | `AsyncStream<PrimerCardFormState>` | Stream of form state changes                                       |
| `presentationContext` | `PresentationContext`              | `.direct` (cancel button) or `.fromPaymentSelection` (back button) |
| `dismissalMechanism`  | `[DismissalMechanism]`             | Supported dismissal methods                                        |
| `cardFormUIOptions`   | `PrimerCardFormUIOptions?`         | UI display options                                                 |
| `selectCountry`       | `PrimerSelectCountryScope`         | Country picker scope                                               |

### Field configurations

Each field has a corresponding `InputFieldConfig?` property:

| Property               | Field           |
| ---------------------- | --------------- |
| `cardNumberConfig`     | Card number     |
| `expiryDateConfig`     | Expiration date |
| `cvvConfig`            | CVV/CVC         |
| `cardholderNameConfig` | Cardholder name |
| `postalCodeConfig`     | Postal/ZIP code |
| `countryConfig`        | Country         |
| `cityConfig`           | City            |
| `stateConfig`          | State/province  |
| `addressLine1Config`   | Address line 1  |
| `addressLine2Config`   | Address line 2  |
| `phoneNumberConfig`    | Phone number    |
| `firstNameConfig`      | First name      |
| `lastNameConfig`       | Last name       |
| `emailConfig`          | Email           |
| `retailOutletConfig`   | Retail outlet   |
| `otpCodeConfig`        | OTP code        |

### Layout customization

| Property                     | Type                                          | Description                                                                 |
| ---------------------------- | --------------------------------------------- | --------------------------------------------------------------------------- |
| `title`                      | `String?`                                     | Form title text                                                             |
| `screen`                     | `CardFormScreenComponent?`                    | Full screen replacement. Signature: `(any PrimerCardFormScope) -> any View` |
| `cardInputSection`           | `Component?`                                  | Card inputs section replacement                                             |
| `billingAddressSection`      | `Component?`                                  | Billing address section replacement                                         |
| `submitButton`               | `Component?`                                  | Submit button section replacement                                           |
| `cobadgedCardsView`          | `(([String], (String) -> Void) -> any View)?` | Co-badged card network selector                                             |
| `errorScreen`                | `ErrorComponent?`                             | Error display replacement                                                   |
| `submitButtonText`           | `String?`                                     | Submit button label                                                         |
| `showSubmitLoadingIndicator` | `Bool`                                        | Show loading spinner on submit                                              |

## Methods

### Field update methods

| Method                                           | Description                             |
| ------------------------------------------------ | --------------------------------------- |
| `updateCardNumber(_ cardNumber: String)`         | Update card number value                |
| `updateCvv(_ cvv: String)`                       | Update CVV value                        |
| `updateExpiryDate(_ expiryDate: String)`         | Update expiry date value                |
| `updateCardholderName(_ cardholderName: String)` | Update cardholder name                  |
| `updatePostalCode(_ postalCode: String)`         | Update postal code                      |
| `updateCity(_ city: String)`                     | Update city                             |
| `updateState(_ state: String)`                   | Update state/province                   |
| `updateAddressLine1(_ addressLine1: String)`     | Update address line 1                   |
| `updateAddressLine2(_ addressLine2: String)`     | Update address line 2                   |
| `updatePhoneNumber(_ phoneNumber: String)`       | Update phone number                     |
| `updateFirstName(_ firstName: String)`           | Update first name                       |
| `updateLastName(_ lastName: String)`             | Update last name                        |
| `updateEmail(_ email: String)`                   | Update email                            |
| `updateCountryCode(_ countryCode: String)`       | Update country code                     |
| `updateSelectedCardNetwork(_ network: String)`   | Select card network for co-badged cards |
| `updateRetailOutlet(_ retailOutlet: String)`     | Update retail outlet                    |
| `updateOtpCode(_ otpCode: String)`               | Update OTP code                         |
| `updateExpiryMonth(_ month: String)`             | Update expiry month                     |
| `updateExpiryYear(_ year: String)`               | Update expiry year                      |

### Generic field access

| Method                                                            | Description               |
| ----------------------------------------------------------------- | ------------------------- |
| `updateField(_ fieldType: PrimerInputElementType, value: String)` | Update any field by type  |
| `getFieldValue(_ fieldType: PrimerInputElementType) -> String`    | Get current field value   |
| `setFieldError(_ fieldType:message:errorCode:)`                   | Set a custom error        |
| `clearFieldError(_ fieldType:)`                                   | Clear a custom error      |
| `getFieldError(_ fieldType:) -> String?`                          | Get current error message |
| `getFormConfiguration() -> CardFormConfiguration`                 | Get field configuration   |

### Validation state

| Method                                                                                        | Description                                                                                                                   |
| --------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
| `updateValidationState(_ field: WritableKeyPath<FieldValidationStates, Bool>, isValid: Bool)` | Update validation state for a specific field. Required when using custom field components via `InputFieldConfig(component:)`. |

Use KeyPaths to specify which field to update:

```swift theme={"dark"}
// Mark the CVV field as valid
scope.updateValidationState(\.cvv, isValid: true)

// Mark the card number field as invalid
scope.updateValidationState(\.cardNumber, isValid: false)
```

<Note>
  When using SDK-provided fields (e.g., `PrimerCardNumberField`, `PrimerCvvField`), validation state is managed automatically.
  You only need to call this method when replacing a field with a custom component.
</Note>

### Actions

| Method     | Description                  |
| ---------- | ---------------------------- |
| `submit()` | Validate and submit the form |
| `onBack()` | Navigate back                |
| `cancel()` | Cancel the card form         |

### ViewBuilder field methods

Each method returns an `AnyView` containing the SDK-managed field:

| Method                      | Parameters                                     |
| --------------------------- | ---------------------------------------------- |
| `PrimerCardNumberField`     | `label: String?, styling: PrimerFieldStyling?` |
| `PrimerExpiryDateField`     | `label: String?, styling: PrimerFieldStyling?` |
| `PrimerCvvField`            | `label: String?, styling: PrimerFieldStyling?` |
| `PrimerCardholderNameField` | `label: String?, styling: PrimerFieldStyling?` |
| `PrimerCountryField`        | `label: String?, styling: PrimerFieldStyling?` |
| `PrimerPostalCodeField`     | `label: String?, styling: PrimerFieldStyling?` |
| `PrimerCityField`           | `label: String?, styling: PrimerFieldStyling?` |
| `PrimerStateField`          | `label: String?, styling: PrimerFieldStyling?` |
| `PrimerAddressLine1Field`   | `label: String?, styling: PrimerFieldStyling?` |
| `PrimerAddressLine2Field`   | `label: String?, styling: PrimerFieldStyling?` |
| `PrimerFirstNameField`      | `label: String?, styling: PrimerFieldStyling?` |
| `PrimerLastNameField`       | `label: String?, styling: PrimerFieldStyling?` |
| `PrimerEmailField`          | `label: String?, styling: PrimerFieldStyling?` |
| `PrimerPhoneNumberField`    | `label: String?, styling: PrimerFieldStyling?` |
| `PrimerRetailOutletField`   | `label: String?, styling: PrimerFieldStyling?` |
| `PrimerOtpCodeField`        | `label: String?, styling: PrimerFieldStyling?` |
| `DefaultCardFormView`       | `styling: PrimerFieldStyling?`                 |

## PrimerCardFormState

```swift theme={"dark"}
public struct PrimerCardFormState: Equatable {
  var configuration: CardFormConfiguration
  var data: FormData
  var fieldErrors: [FieldError]
  var isLoading: Bool
  var isValid: Bool
  var selectedCountry: PrimerCountry?
  var selectedNetwork: PrimerCardNetwork?
  var availableNetworks: [PrimerCardNetwork]
  var surchargeAmountRaw: Int?
  var surchargeAmount: String?
  var displayFields: [PrimerInputElementType]
}
```

| Property            | Type                       | Description                            |
| ------------------- | -------------------------- | -------------------------------------- |
| `isValid`           | `Bool`                     | All required fields pass validation    |
| `isLoading`         | `Bool`                     | Form is submitting                     |
| `fieldErrors`       | `[FieldError]`             | Current validation errors              |
| `selectedNetwork`   | `PrimerCardNetwork?`       | Detected card network                  |
| `availableNetworks` | `[PrimerCardNetwork]`      | Available networks for co-badged cards |
| `displayFields`     | `[PrimerInputElementType]` | Fields to display                      |
| `selectedCountry`   | `PrimerCountry?`           | Selected billing country               |
| `surchargeAmount`   | `String?`                  | Formatted surcharge amount             |

## See also

<CardGroup cols={2}>
  <Card title="Card Form Layout Builder" icon="credit-card" href="/checkout/primer-checkout/build-your-ui/card-form-layout-builder">
    Interactive card form layout builder
  </Card>

  <Card title="Build a custom card form" icon="hammer" href="/checkout/primer-checkout/guides-and-recipes/build-custom-card-form">
    Step-by-step guide
  </Card>
</CardGroup>
