# Implementation

Learn how to use card components in your project.

## Overview

Every component follows the same basic three-step lifecycle:

1. Create the component and optionally add your own configuration.
2. Mount the component. This is what makes the component visible and interactive.
3. Unmount the component. This is a clean-up step that clears up resources.


## Before you start

To use card components, you need to [install Components for Web](/guides/components/web/install).

## Step 1: Initialise the SDK

To get started, initialise the Checkout SDK.


```typescript
const pxpCheckoutSdk = PxpCheckout.initialize({
  environment: "test",
  session: sessionData,
  ownerId: "Unity",
  ownerType: "MerchantGroup",
  transactionData: {
    currency: "USD" as CurrencyType,
    amount: 25,
    entryType: "Ecom",
    intent: {
      card: "Authorisation",
      paypal: "Authorisation"
    },
    merchantTransactionId: crypto.randomUUID(),
    merchantTransactionDate: () => new Date().toISOString(),
  },
  onGetShopper: () => {
    // Return current shopper data dynamically
    return Promise.resolve({
      id: 'shopper-09',
      email: 'customer@example.com',
      firstName: 'John',
      lastName: 'Doe',
      phoneNumber: '+1-555-0123'
    });
  },
  onGetShippingAddress: () => {
    // Return current shipping address dynamically
    return Promise.resolve({
      address: '123 Main Street',
      city: 'New York',
      state: 'NY',
      postalCode: '10001',
      countryCode: 'US'
    });
  }
})
```

| Property | Description |
|  --- | --- |
| `environment`string | The environment type.Possible values:`test``live` |
| `session`sessionData | Details about the checkout session. |
| `ownerId`string | Your unique merchant group identifier, as assigned by PXP. You can find it in the Unity Portal, by going to **Merchant setup > Merchant groups** and checking the *Merchant group ID* column or by clicking on a site and checking the *General information* section. |
| `ownerType`string | The type of owner. Set this to `MerchantGroup`. Possible values:`MerchantGroup``Merchant`  `Site`   |
| `onGetShopper`function | Callback function to provide shopper data dynamically. Returns a Promise with shopper information including ID, email, name, and contact details. This is used for card tokenisation and transaction processing. |
| `onGetShippingAddress`function | Callback function to provide shipping address data dynamically. Returns a Promise with current shipping address information. This is used when shipping information is required for the transaction. |
| `transactionData`object | Details about the transaction. |
| `transactionData.currency`string (1-3 characters) | The currency code associated with the transaction, in ISO 4217 format. |
| `transactionData.amount`number | The transaction amount. |
| `transactionData.entryType`string | The entry type.Possible values:`Ecom``MOTO` |
| `transactionData.intent`object | The transaction intents for each payment method. [Learn more about intents](/guides/components/web/card/how-it-works#supported-transaction-intents). |
| `transactionData.intent.card`string | The intent for card transactions.Possible values:`Authorisation``EstimatedAuthorisation``Purchase``Payout``Verification` |
| `transactionData.intent.paypal`string | The intent for PayPal transactions.Possible values:`Authorisation``Purchase` |
| `transactionData.merchantTransactionId`string | A unique identifier for this transaction. |
| `transactionData.merchantTransactionDate`string | The date and time of the transaction, in ISO 8601 format. |


## Step 2: Create a component

Next, you're going to create a component. Use the following snippet and change `component-name` to the name of the component you want to add. For example, `new-card` for the new card component.


```typescript
const component = sdk.create('component-name');
```

View list of component names
Pre-built components:

* `card-on-file`
* `click-once`
* `billing-address`
* `new-card`


Standalone components:

* `card-number`
* `card-expiry-date`
* `card-cvc`
* `card-holder-name`
* `card-brand-selector`
* `card-consent`
* `dynamic-card-image`
* `card-submit`
* `country-selection`
* `postcode`
* `address`
* `prefill-billing-address-checkbox`


## Step 3: Add the corresponding HTML container

To render the component, add the corresponding HTML container. Use the following snippet and change `component-name` to the name of the component you want to add. For example, `new-card-container` for the new card component.


```html
<div id="container-name"></div>
```

View list of container names
Pre-built components:

* `card-on-file-container`
* `click-once-container`
* `billing-address-container`
* `new-card-container`


Standalone components:

* `card-number-container`
* `card-expiry-date-container`
* `card-cvc-container`
* `card-holder-name-container`
* `card-brand-selector-container`
* `card-consent-container`
* `dynamic-card-image-container`
* `card-submit-container`
* `country-container`
* `postcode-container`
* `address-container`
* `prefill-billing-address-checkbox-container`


## Step 4: Mount the component

For the component to be visible and functional, you need to mount it. Use the following snippet, and replace both the component name (e.g., `NewCard`) and the container name (e.g., `new-card-container`).


```typescript
componentName.mount('container-name');
```

At this point, your component is ready to use.

## Step 5: Unmount the component

Lastly, remember to unmount the component when it's no longer needed.


```typescript
componentName.unmount('container-name');
```

## What's next?

### Customise the look and feel

You can configure the appearance and behaviour of components to fit your brand. We've documented all configurable parameters for each component in the [Customisation](/guides/components/web/card/about-customisation) section.


```typescript
const cardNumber = sdk.create('card-number', {
  placeholder: 'Enter card number',
  label: 'Card number',
  required: true,
  acceptedCardBrands: ['visa', 'mastercard', 'amex'],
  styles: {
    base: { fontSize: '16px', color: '#333' },
    invalid: { borderColor: 'red' }
  }
});
```

### Add event handling

Components emit events based on user interaction or validation. You can implement callback functions to handle these events and perform actions, such as display success and error messages. For more details about event handling, see the [Events](/guides/components/web/card/events) page.


```typescript
const newCard = sdk.create('new-card', {
  onChange: (state) => console.log('Component state changed'),
  onValidation: (data) => console.log('Overall validation'),
  fields: {
    cardNumber: {
      onChange: (event) => console.log('Card number changed'),
      onValidationFailed: (data) => console.log('Card number invalid')
    }
  }
});
```

### Implement analytics tracking

Components automatically trigger analytics events when significant actions or states occur. You can consume these events to gather real-time insights, such as tracking payment completion times. For more details about analytics tracking, see the [Analytics](/guides/components/web/card/analytics) page.


```typescript
if (analyticsEvent instanceof ClickOncePaymentCompletionTimeAnalyticsEvent) {
  const completionTime = analyticsEvent.duration;
  if (completionTime > 5000) { // Alert if over 5s
    alertPerformanceTeam(analyticsEvent);
  }
}
```

### Add error handling

Error handling is crucial for payment components because they deal with sensitive financial data and complex validation rules. They can happen due to issues with configuration, validation, authentication, or connectivity. For more details about error handling, see the [Errors](/guides/components/errors) page.


```typescript
try {
  const component = sdk.create('new-card');
  component.mount('card-container');
} catch (error) {
  console.error('Failed to initialise payment component:', error);
  // Show fallback UI or error message to user
}
```

## Complete example

Here's a complete example of the new card component being added to a website.


```html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Simple Payment Example</title>
  <style>
    body {
      font-family: Arial, sans-serif;
      max-width: 600px;
      margin: 50px auto;
      padding: 20px;
      background-color: #f5f5f5;
    }

    .payment-container {
      background: white;
      padding: 30px;
      border-radius: 8px;
      box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
    }

    h1 {
      text-align: center;
      color: #333;
      margin-bottom: 30px;
    }

    #new-card-container {
      margin: 20px 0;
    }
  </style>
</head>
<body>
  <div class="payment-container">
    <h1>Complete your payment</h1>
    
    <!-- The new card component will be mounted here -->
    <div id="new-card-container"></div>
  </div>

  <!-- Link to the SDK script -->
  <script src="https://your-domain.com/pxp-checkout-sdk.js"></script>
  
  <script>
    // Simple analytics function
    function trackEvent(eventName, data) {
      console.log('Analytics:', eventName, data);
    }

    // Initialise when page loads
    document.addEventListener('DOMContentLoaded', function() {
      // Initialise the SDK
      const pxpSdk = PxpCheckout.initialize({
        environment: 'sandbox',
        session: {
          sessionId: 'your-session-id-here',
          hmacKey: 'your-hmac-key-here',
          encryptionKey: 'your-encryption-key-here',
          allowedFundingTypes: {
            cards: ['visa', 'mastercard', 'amex']
          }
        },
        merchantShopperId: 'shopper-123',
        ownerType: 'MerchantGroup',
        ownerId: 'owner-123',
        transactionData: {
          amount: 1000,
          currency: 'USD',
          entryType: 'Ecom',
          intent: {
            card: 'Authorisation',
            paypal: 'Authorisation'
          },
          merchantTransactionId: 'txn-' + Date.now(),
          merchantTransactionDate: () => new Date().toISOString()
        }
      });

      // Create the new card component
      const newCardComponent = pxpSdk.create('new-card', {
        fields: {
          cardNumber: {
            required: true,
            placeholder: '1234 5678 9012 3456',
            inputStyles: {
              base: {
                border: '2px solid #ddd',
                borderRadius: '6px',
                padding: '12px',
                fontSize: '16px'
              },
              focus: {
                borderColor: '#4CAF50',
                outline: 'none'
              }
            },
            onCardBrandDetected: function(event) {
              trackEvent('card_brand_detected', { brand: event.cardBrand });
            }
          },
          expiryDate: {
            required: true,
            placeholder: 'MM/YY',
            inputStyles: {
              base: {
                border: '2px solid #ddd',
                borderRadius: '6px',
                padding: '12px',
                fontSize: '16px'
              },
              focus: {
                borderColor: '#4CAF50',
                outline: 'none'
              }
            }
          },
          cvc: {
            required: true,
            placeholder: '123',
            inputStyles: {
              base: {
                border: '2px solid #ddd',
                borderRadius: '6px',
                padding: '12px',
                fontSize: '16px'
              },
              focus: {
                borderColor: '#4CAF50',
                outline: 'none'
              }
            }
          },
          cardHolderName: {
            required: true,
            placeholder: 'John Doe',
            inputStyles: {
              base: {
                border: '2px solid #ddd',
                borderRadius: '6px',
                padding: '12px',
                fontSize: '16px'
              },
              focus: {
                borderColor: '#4CAF50',
                outline: 'none'
              }
            },
            onChange: function(event) {
              trackEvent('cardholder_name_changed', { length: event.target.value.length });
            }
          }
        },
        submitButton: {
          text: 'Pay $10.00',
          style: {
            backgroundColor: '#4CAF50',
            border: 'none',
            padding: '15px',
            borderRadius: '6px',
            color: 'white',
            fontSize: '16px',
            fontWeight: 'bold',
            cursor: 'pointer',
            width: '100%',
            marginTop: '10px'
          },
          hoverStyle: {
            backgroundColor: '#45a049'
          }
        },
        onPostAuthorisation: async function(data) {
          console.log('Transaction completed');
          console.log('Merchant Transaction ID:', data.merchantTransactionId);
          console.log('System Transaction ID:', data.systemTransactionId);
          
          // Get full result from backend
          const result = await getAuthorisationResultFromGateway(data.merchantTransactionId, data.systemTransactionId);
          
          if (result.state === 'Authorised' || result.state === 'Captured') {
            trackEvent('payment_success', { 
              merchantTransactionId: data.merchantTransactionId,
              amount: 1000 
            });
            alert('Payment successful!');
          } else {
            trackEvent('payment_failed', { 
              merchantTransactionId: data.merchantTransactionId,
              state: result.state 
            });
            alert('Payment failed. Please try again.');
          }
        }
      });

      // Mount the component
      newCardComponent.mount('new-card-container');

      // Unmount the component when the page is being unloaded
      window.addEventListener('beforeunload', function() {
        newCardComponent.unmount();
      });
    });
  </script>
</body>
</html>
```