checkout.addEventListener('primer:ready', (event) => { const primer = event.detail; const user = getAuthenticatedUser(); if (user?.fullName) { primer.setCardholderName(user.fullName); }});
val checkout = rememberPrimerCheckoutController(clientToken)val cardFormController = rememberCardFormController(checkout)LaunchedEffect(cardFormController) { cardFormController.updateCardholderName(userProfile.fullName)}
@StateObject private var session: PrimerCheckoutSessioninit(clientToken: String) { _session = StateObject(wrappedValue: PrimerCheckoutSession(clientToken: clientToken))}var body: some View { ScrollView { PrimerCardForm() } .primerCheckoutSession(session) { state in // Handle .success and .dismissed. After .ready, a .failure ends one attempt and the customer can retry. } .onChange(of: session.phase) { phase in guard phase == .ready, let cardForm = session.cardForm else { return } // The client session already carries the customer you attached on your backend. let customer = session.clientSession?.customer let name = [customer?.firstName, customer?.lastName] .compactMap { $0 } .joined(separator: " ") if !name.isEmpty { cardForm.updateCardholderName(name) } }}
Listen for the primer:ready event to access the Primer SDK instance
Retrieve the user’s name from your authentication system or profile data
Call primer.setCardholderName() with the name value
When using setCardholderName(), you don’t need to include the <primer-input-card-holder-name> component in your form if you don’t want users to edit the name.
Create a PrimerCardFormController using rememberCardFormController()
Call updateCardholderName() with the user’s name inside a LaunchedEffect
The field will display the prefilled name and the user can edit it if needed
updateCardholderName() sets the field value programmatically. The customer can still edit the prefilled name. The same approach works for other fields — use updateCardNumber(), updateExpiryDate(), or updateCvv() as needed.
Hold a PrimerCheckoutSession as a @StateObject and apply the .primerCheckoutSession(_:theme:onCompletion:) modifier
Once the session reaches .ready, read the customer from session.clientSession — these are the details you attached when you created the client session, so there is nothing to pass in from your own screen
The cardForm sub-session (a PrimerCardFormSession) is available at the same point — call updateCardholderName() on it
The field shows the name, the customer can still edit it, and the form counts the field as filled, so the submit button is not held back
Every property on the client session is optional, so build the name defensively — a session created
without a customer leaves the field untouched rather than writing an empty string.
The other setters on PrimerCardFormSession work the same way: updateCardNumber(),
updateExpiryDate(), updateCvv(), updateFirstName(), updateLastName(),
updateAddressLine1(), updateAddressLine2(), updateCity(), updateState(),
updatePostalCode(), updatePhoneNumber() and updateCountryCode(). Each one changes what its
field shows and counts the field as filled. updateCountryCode() takes a country code such as "GB". If the
SDK does not recognize the code, the country field stays as it was. A write that lands while the
customer is typing in a text field does not override their keystrokes.The values you read back are redacted: cardForm.state carries the card number masked to its BIN and
last four digits, and never carries the CVV.
checkout.addEventListener('primer:ready', (event) => { const primer = event.detail; // Get name from shipping form const shippingName = document.getElementById('shipping-name').value; if (shippingName) { primer.setCardholderName(shippingName); }});
If you want to pre-fill but still allow editing, include the cardholder name input and set an initial value:
Web
Android
iOS
checkout.addEventListener('primer:ready', (event) => { const primer = event.detail; const user = getAuthenticatedUser(); if (user?.fullName) { // Pre-fill the value primer.setCardholderName(user.fullName); // The <primer-input-card-holder-name> component will show this value // and users can still edit it }});
val state by checkout.state.collectAsStateWithLifecycle()LaunchedEffect(state) { when (state) { is PrimerCheckoutState.Success -> { } is PrimerCheckoutState.Failure -> { } else -> Unit }}PrimerCheckoutHost( checkout = checkout,) { val cardFormController = rememberCardFormController(checkout) LaunchedEffect(cardFormController) { cardFormController.updateCardholderName(userProfile.fullName) } PrimerCardForm( controller = cardFormController, cardDetails = { Column { CardFormDefaults.CardholderField(cardFormController) Spacer(Modifier.height(8.dp)) CardFormDefaults.CardNumberField(cardFormController) Spacer(Modifier.height(8.dp)) Row(Modifier.fillMaxWidth()) { CardFormDefaults.ExpiryField( cardFormController, Modifier.weight(1f), ) Spacer(Modifier.width(8.dp)) CardFormDefaults.CvvField( cardFormController, Modifier.weight(1f), ) } } }, )}
The prefilled field is always editable. Recomposing the cardDetails slot is how you decide where
the name sits — here it leads the form, so the customer sees what was filled in for them first:
struct PrefilledCardFormScreen: View { @StateObject private var session: PrimerCheckoutSession init(clientToken: String) { _session = StateObject(wrappedValue: PrimerCheckoutSession(clientToken: clientToken)) } var body: some View { ScrollView { PrimerCardForm(cardDetails: { formSession in VStack(spacing: 16) { CardFormDefaults.cardholderName(formSession) CardFormDefaults.cardNumber(formSession) HStack(spacing: 12) { CardFormDefaults.expiryDate(formSession) CardFormDefaults.cvv(formSession) } CardFormDefaults.cardNetwork(formSession) } .padding() }) } .primerCheckoutSession(session) { state in // Handle .success and .dismissed. After .ready, a .failure ends one attempt and the customer can retry. } .onChange(of: session.phase) { phase in guard phase == .ready, let cardForm = session.cardForm else { return } let customer = session.clientSession?.customer let name = [customer?.firstName, customer?.lastName] .compactMap { $0 } .joined(separator: " ") if !name.isEmpty { cardForm.updateCardholderName(name) } } }}
When you recompose the individual card fields, add CardFormDefaults.cardNetwork(formSession) so co-badged cards still get a network selector — the built-in one is suppressed once you replace the default cardDetails section.