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.
CardFormDefaults exposes a set of per-field building blocks alongside its full section renderers. Each building block is a static function with the signature (PrimerCardFormSession) -> CardFieldContent. Drop any of them into a custom PrimerCardForm section slot to recompose the form one field at a time, while keeping the SDK’s built-in formatting, validation, keyboard configuration, and inline error display.
Every building block is self-hiding: it renders nothing unless its field is part of the active CardFormConfiguration for the current session. You can drop every block into a layout without worrying about which fields the current session actually requires — only the configured ones appear.

How the building blocks work

The full-section renderers — CardFormDefaults.cardDetails(_:) and CardFormDefaults.billingAddress(_:) — produce the complete, config-aware form. The field-level building blocks let you interleave your own content (banners, headings, custom layout) between individual fields instead. Each field block forwards to the same shared, configuration-aware renderer the section helpers use, so a hand-composed layout behaves identically to the default form. The block checks whether its field appears in the session’s configuration.cardFields or configuration.billingFields; if not, it resolves to an EmptyView.
All field blocks take a single unlabeled PrimerCardFormSession parameter and return a concrete View. Read session.state for rendering and call into the session for mutations and submission.

Card detail fields

These map to the cardFields in the active CardFormConfiguration (the default configuration is .cardNumber, .expiryDate, .cvv, .cardholderName).

Co-badged card network selector

cardNetwork(_:) is a standalone selector for co-badged cards. Unlike the other blocks it does not read CardFormConfiguration; it renders only when more than one network is detected (session.state.availableNetworks.count > 1), reusing the SDK’s built-in dropdown. Tapping a network commits the choice through session.selectCardNetwork(_:).
Use cardNetwork(_:) only when you recompose the individual card fields. The full cardDetails(_:) section already renders the selector when multiple networks are detected — combining the two would show two selectors.

Billing address fields

These map to the billingFields in the active CardFormConfiguration. They appear only when billing address collection is enabled for the session (configuration.requiresBillingAddress and the corresponding field present in billingFields).

Composing a custom card detail layout

Pass a @ViewBuilder closure to the cardDetails slot on PrimerCardForm. Lay out the field blocks in any order, and add your own content between them. Because each block is self-hiding, the extra fields you reference (such as cardholderName) appear only if the session’s configuration includes them.
Because you replaced the default cardDetails section, include CardFormDefaults.cardNetwork(session) so co-badged cards still get a selector — the built-in one is suppressed once you recompose the individual fields.

Recomposing billing fields too

The billingAddress slot works the same way. Group billing blocks into your own layout; only the configured fields render.

Reacting to field state

Each building block manages its own input and inline error display, so you don’t have to wire bindings manually. When you need to react to the form as a whole — for example to drive your own submit button — read the published session.state:
Per-field errors are available on session.state via fieldErrors, hasError(for:), and errorMessage(for:). See Card Form Session for the full state surface.

See also

Card Form Defaults

The full section renderers and submit button these blocks complement.

PrimerCardForm

The composable form view and its @ViewBuilder section slots.

Card Form Session

Observable state, field updates, and submission for the card form.