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

# PrimerCardForm

> SwiftUI card payment form view with slot-based layout

<Warning>
  Primer Checkout iOS SDK is currently in **beta** (v3.0.0-beta.1).
  The API is subject to change before the stable release.
</Warning>

`PrimerCardForm` is a SwiftUI `View` that renders a complete card payment form, composed from three section slots: card details, billing address, and submit button. Each section is a `@ViewBuilder` slot you can replace.

The form resolves its [`PrimerCardFormSession`](/docs/sdk/ios-checkout/v3.0.0-beta/api/card-form/card-form-session) from the environment (provided by the `.primerCheckoutSession(_:onCompletion:)` modifier), so it can be embedded anywhere — inside the modal [`PrimerCheckout`](/docs/sdk/ios-checkout/v3.0.0-beta/api/primer-checkout) or inline in your own layout.

<Info>
  Requires iOS 15.0+. `PrimerCardForm` is `@available(iOS 15.0, *)`.
</Info>

## Signature

```swift theme={"dark"}
@available(iOS 15.0, *)
public struct PrimerCardForm<CardDetails: View, Billing: View, Submit: View>: View {

  public init(
    @ViewBuilder cardDetails: @escaping (PrimerCardFormSession) -> CardDetails = { CardFormDefaults.cardDetails($0) },
    @ViewBuilder billingAddress: @escaping (PrimerCardFormSession) -> Billing = { CardFormDefaults.billingAddress($0) },
    @ViewBuilder submitButton: @escaping (PrimerCardFormSession) -> Submit = { CardFormDefaults.submitButton($0) }
  )
}
```

## Parameters

| Parameter        | Type                                     | Default                                   | Description                                                                      |
| ---------------- | ---------------------------------------- | ----------------------------------------- | -------------------------------------------------------------------------------- |
| `cardDetails`    | `(PrimerCardFormSession) -> CardDetails` | `{ CardFormDefaults.cardDetails($0) }`    | Slot for the card input fields (number, expiry, CVV, cardholder name).           |
| `billingAddress` | `(PrimerCardFormSession) -> Billing`     | `{ CardFormDefaults.billingAddress($0) }` | Slot for the billing address fields. Only rendered when required by the session. |
| `submitButton`   | `(PrimerCardFormSession) -> Submit`      | `{ CardFormDefaults.submitButton($0) }`   | Slot for the submit/pay button.                                                  |

Each slot receives the active [`PrimerCardFormSession`](/docs/sdk/ios-checkout/v3.0.0-beta/api/card-form/card-form-session), which exposes the published `state` and the field-update and `submit()` methods you need to drive custom UI.

<Note>
  Every slot is generic and defaults to a [`CardFormDefaults`](/docs/sdk/ios-checkout/v3.0.0-beta/api/card-form/card-form-defaults) builder. Because the defaults are supplied per-parameter, you can override any single slot and leave the rest at their default styling — you never have to re-implement the whole form.
</Note>

## Default layout

The default form stacks the three slots vertically:

| Order | Slot             | Default content                                                                                          |
| ----- | ---------------- | -------------------------------------------------------------------------------------------------------- |
| 1     | `cardDetails`    | `CardFormDefaults.cardDetails` — card number, expiry, CVV, cardholder name                               |
| 2     | `billingAddress` | `CardFormDefaults.billingAddress` — billing address fields, rendered only when the session requires them |
| 3     | `submitButton`   | `CardFormDefaults.submitButton` — the pay button                                                         |

If no session is available in the environment, the form renders `CardFormDefaults.unavailable()` instead.

## Usage

### Default form

Render the fully styled default card form with no arguments:

```swift theme={"dark"}
import SwiftUI
import PrimerSDK

struct CardPaymentScreen: View {
  var body: some View {
    PrimerCardForm()
  }
}
```

<Tip>
  Place `PrimerCardForm()` inside a view that has the `.primerCheckoutSession(_:onCompletion:)` modifier applied, so the form can resolve its `PrimerCardFormSession` from the environment.
</Tip>

### Overriding a single slot

To customize one section, pass a **labeled** argument and leave the others at their defaults. Here only the submit button is replaced — `cardDetails` and `billingAddress` keep the default styling:

```swift theme={"dark"}
PrimerCardForm(submitButton: { session in
  MyPayButton(isLoading: session.state.isLoading) {
    session.submit()
  }
})
```

<Warning>
  A bare trailing closure binds to the **last** slot — `submitButton`. To override `cardDetails` or `billingAddress`, always use the labeled argument form (`cardDetails:` / `billingAddress:`). For example, `PrimerCardForm { session in ... }` customizes the submit button, not the card fields.
</Warning>

### Recomposing the card section from building blocks

You don't have to discard the default fields when customizing a slot. Compose the default content with your own views using the per-field builders on [`CardFormDefaults`](/docs/sdk/ios-checkout/v3.0.0-beta/api/card-form/card-form-defaults):

```swift theme={"dark"}
PrimerCardForm(cardDetails: { session in
  VStack {
    CardFormDefaults.cardDetails(session)
    MyPromoBanner()
  }
})
```

You can also assemble the card section from the individual field building blocks — `CardFormDefaults.cardNumber`, `expiryDate`, `cvv`, and `cardholderName`:

```swift theme={"dark"}
PrimerCardForm(cardDetails: { session in
  VStack(spacing: 16) {
    CardFormDefaults.cardNumber(session)
    HStack(spacing: 16) {
      CardFormDefaults.expiryDate(session)
      CardFormDefaults.cvv(session)
    }
    CardFormDefaults.cardholderName(session)
  }
})
```

See [Card field components](/docs/sdk/ios-checkout/v3.0.0-beta/api/card-form/card-field-components) for the full set of field building blocks.

## See also

<CardGroup cols={2}>
  <Card title="PrimerCardFormSession" icon="diagram-project" href="/docs/sdk/ios-checkout/v3.0.0-beta/api/card-form/card-form-session">
    State, field-update methods, and `submit()` passed into every slot.
  </Card>

  <Card title="CardFormDefaults" icon="layer-group" href="/docs/sdk/ios-checkout/v3.0.0-beta/api/card-form/card-form-defaults">
    Default section and field builders used by each slot.
  </Card>

  <Card title="Card field components" icon="input-text" href="/docs/sdk/ios-checkout/v3.0.0-beta/api/card-form/card-field-components">
    Individual field building blocks for recomposing the card section.
  </Card>

  <Card title="PrimerPaymentMethods" icon="credit-card" href="/docs/sdk/ios-checkout/v3.0.0-beta/api/payment-methods/primer-payment-methods">
    Render the list of available payment methods alongside the card form.
  </Card>
</CardGroup>
