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

<Tabs>
  <Tab title="Web">
    ```javascript theme={"dark"}
    checkout.addEventListener('primer:ready', (event) => {
      const primer = event.detail;

      const user = getAuthenticatedUser();
      if (user?.fullName) {
        primer.setCardholderName(user.fullName);
      }
    });
    ```
  </Tab>

  <Tab title="Android">
    ```kotlin theme={"dark"}
    val checkout = rememberPrimerCheckoutController(clientToken)
    val cardFormController = rememberCardFormController(checkout)

    LaunchedEffect(cardFormController) {
        cardFormController.updateCardholderName(userProfile.fullName)
    }
    ```
  </Tab>

  <Tab title="iOS">
    ```swift theme={"dark"}
    @StateObject private var session = PrimerCheckoutSession(clientToken: clientToken)

    var body: some View {
      ScrollView {
        PrimerCardForm()
      }
      .primerCheckoutSession(session) { state in
        // Handle the terminal PrimerCheckoutState
      }
      .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)
        }
      }
    }
    ```
  </Tab>
</Tabs>

## How it works

<Tabs>
  <Tab title="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

    <Info>
      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.
    </Info>
  </Tab>

  <Tab title="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.
    </Note>
  </Tab>

  <Tab title="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`](/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`](/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 billing-address setters behave the same way: `updateFirstName()`, `updateLastName()`,
      `updateAddressLine1()`, `updateAddressLine2()`, `updateCity()`, `updateState()`,
      `updatePostalCode()` and `updatePhoneNumber()` all change what their field shows.

      `updateCardNumber()`, `updateCvv()`, `updateExpiryDate()` and `updateCountryCode()` set the value
      used for payment but leave the visible field as the customer left it. For the card number and CVV
      that is deliberate: the SDK never hands either back to your code, so it has nothing to write into
      the field.
    </Note>
  </Tab>
</Tabs>

## Variations

### Pre-fill from shipping address

<Tabs>
  <Tab title="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>

  <Tab title="Android">
    ```kotlin theme={"dark"}
    LaunchedEffect(cardFormController) {
        cardFormController.updateCardholderName(shippingAddress.fullName)
    }
    ```
  </Tab>

  <Tab title="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)
      }
    }
    ```
  </Tab>
</Tabs>

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

<Tabs>
  <Tab title="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>

  <Tab title="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>

  <Tab title="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 the terminal PrimerCheckoutState
        }
        .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.
    </Note>
  </Tab>
</Tabs>

## See also

<CardGroup cols={2}>
  <Card title="Build a custom card form" icon="credit-card" href="/docs/checkout/primer-checkout/guides-and-recipes/build-custom-card-form">
    Step-by-step guide to building a fully custom card form
  </Card>

  <Card title="SDK options" icon="gear" href="/docs/checkout/primer-checkout/configuration/sdk-options">
    All available SDK configuration options
  </Card>
</CardGroup>


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