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

# Pre-fill cardholder name

> Automatically fill in the cardholder name from user profile data.

Pre-populate the cardholder name field with data from your user's profile to reduce friction at checkout.

## Recipe

> [tab] Web
>
> ```javascript theme={"dark"}
> checkout.addEventListener('primer:ready', (event) => {
>   const primer = event.detail;
>
>   const user = getAuthenticatedUser();
>   if (user?.fullName) {
>     primer.setCardholderName(user.fullName);
>   }
> });
> ```

> [tab] Android
>
> ```kotlin theme={"dark"}
> val checkout = rememberPrimerCheckoutController(clientToken)
> val cardFormController = rememberCardFormController(checkout)
>
> LaunchedEffect(cardFormController) {
>     cardFormController.updateCardholderName(userProfile.fullName)
> }
> ```

> [tab] iOS
>
> ```swift theme={"dark"}
> @StateObject private var session: PrimerCheckoutSession
>
> init(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)
>     }
>   }
> }
> ```

## How it works

> [tab] Web
>
> 1. Listen for the `primer:ready` event to access the Primer SDK instance
>
> 2. Retrieve the user's name from your authentication system or profile data
>
> 3. Call `primer.setCardholderName()` with the name value
>
> > [!NOTE]
> >
> > 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.

> [tab] Android
>
> 1. Create a `PrimerCardFormController` using `rememberCardFormController()`
>
> 2. Call `updateCardholderName()` with the user's name inside a `LaunchedEffect`
>
> 3. The field will display the prefilled name and the user can edit it if needed
>
> > [!NOTE]
> >
> > `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.

> [tab] iOS
>
> 1. Hold a `PrimerCheckoutSession` as a `@StateObject` and apply the `.primerCheckoutSession(_:theme:onCompletion:)` modifier
> 2. Once the session reaches `.ready`, read the customer from [`session.clientSession`](https://primer.io/docs/sdk/ios-checkout/v3.0.0-beta/api/primer-checkout-state#primerclientsession) -- these are the details you attached when you created the client session, so there is nothing to pass in from your own screen
> 3. The `cardForm` sub-session (a [`PrimerCardFormSession`](https://primer.io/docs/sdk/ios-checkout/v3.0.0-beta/api/card-form/card-form-session)) is available at the same point -- call `updateCardholderName()` on it
> 4. 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.
>
> > [!NOTE]
> >
> > 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.

## Variations

### Pre-fill from shipping address

> [tab] Web
>
> ```javascript theme={"dark"}
> 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);
>   }
> });
> ```

> [tab] Android
>
> ```kotlin theme={"dark"}
> LaunchedEffect(cardFormController) {
>     cardFormController.updateCardholderName(shippingAddress.fullName)
> }
> ```

> [tab] iOS
>
> ```swift theme={"dark"}
> .onChange(of: session.phase) { phase in
>   guard phase == .ready, let cardForm = session.cardForm else { return }
>
>   let shipping = session.clientSession?.customer?.shippingAddress
>   let name = [shipping?.firstName, shipping?.lastName]
>     .compactMap { $0 }
>     .joined(separator: " ")
>
>   if !name.isEmpty {
>     cardForm.updateCardholderName(name)
>   }
> }
> ```

### Pre-fill with editable field

If you want to pre-fill but still allow editing, include the cardholder name input and set an initial value:

> [tab] Web
>
> ```javascript theme={"dark"}
> 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
>   }
> });
> ```

> [tab] Android
>
> ```kotlin theme={"dark"}
> 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),
>                     )
>                 }
>             }
>         },
>     )
> }
> ```

> [tab] iOS
>
> 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:
>
> ```swift theme={"dark"}
> 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)
>       }
>     }
>   }
> }
> ```
>
> > [!NOTE]
> >
> > 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.

## See also

> [card] [Build a custom card form](https://primer.io/docs/checkout/primer-checkout/guides-and-recipes/build-custom-card-form.md)
>
> Step-by-step guide to building a fully custom card form

> [card] [SDK options](https://primer.io/docs/checkout/primer-checkout/configuration/sdk-options.md)
>
> All available SDK configuration options


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.