# Click-once

Learn about customisation options for the click-once component.

## Styling


```typescript
const clickOnceConfig: ClickOnceComponentConfig = {
  limitTokens: number,
  filterBy: {
    excludeExpiredTokens: boolean,
    schemes: string[],
    fundingSource: string,
    issuerCountryCode: string,
    ownerType: string
  },
  orderBy: {
    expiryDate: string,
    scheme: string,
    fundingSource: string,
    ownerType: string,
    issuerCountryCode: string,
    lastUsageDate: {
      orderByField: string
    }
  },
  cardBrandImages: {
    visaSrc: string,
    mastercardSrc: string,
    amexSrc: string,
    cupSrc: string,
    dinersSrc: string,
    discoverSrc: string,
    jcbSrc: string
  },
  isCvcRequired: boolean,
  cvcComponentConfig: CardCvcComponentConfig,
  cardSubmitComponentConfig: CardSubmitComponentConfig,
  hideCardBrandLogo: boolean,
  submitButtonText: string,
  disableCardSelection: boolean,
  isRenderLastPurchaseCard: boolean,
  isRenderLastPayoutCard: boolean,
  class: string,
  selectTokenItemClass: string,
  useTransparentCardBrandImage: boolean,
  selectCardButtonAriaLabel: string,
  label: string,
  labelAriaLabel: string,
  submitAriaLabel: string,
  cardNumberAriaLabel: string,
  cardExpiryDateAriaLabel: string,
  transactionInitiatorType: TransactionInitiatorType,
  externalTokenId: string
}
```

| Parameter | Description |
|  --- | --- |
| `limitTokens`number | The maximum number of tokens to display in the component. |
| `filterBy`object | Details about the filtering options. |
| `filterBy.excludeExpiredTokens`boolean | Whether to exclude tokens associated with expired cards. |
| `filterBy.schemes`string [] | The list of card schemes to include. For example, `[Visa, Mastercard]`. |
| `filterBy.fundingSource`string | The funding source type to include. For example `Credit` or `Debit`. |
| `filterBy.issuerCountryCode`string | The issuer country code to include. |
| `filterBy.ownerType`string | The owner type to include. |
| `orderBy`object | Details about the ordering options. |
| `orderBy.expiryDate`object | Details for ordering by expiry date. |
| `orderBy.expiryDate.direction`string | The direction to order by.Possible values:`desc``asc` |
| `orderBy.expiryDate.priority`number | The priority of the ordering option. |
| `orderBy.scheme`object | Details for ordering by card scheme. |
| `orderBy.scheme.valuesOrder`string | The card scheme. |
| `orderBy.scheme.priority`number | The priority of the ordering option. |
| `orderBy.fundingSource`object | Details for ordering by funding source. |
| `orderBy.fundingSource.valuesOrder`string | The funding source.Possible values:CreditDebit |
| `orderBy.fundingSource.priority`number | The priority of the ordering option. |
| `orderBy.ownerType`object | Details for ordering by owner type. |
| `orderBy.ownerType.valuesOrder`string | The owner type.Possible values:`Consumer``Commercial` |
| `orderBy.ownerType.priority`number | The priority of the ordering option. |
| `orderBy.issuerCountryCode`object | Details for ordering by issuer country code. |
| `orderBy.issuerCountryCode.direction`string | The direction to order by.Possible values:`desc``asc` |
| `orderBy.lastUsageDate`object | Details for ordering by last usage date. |
| `orderBy.lastUsageDate.direction`string | The direction to order by.Possible values:`desc``asc` |
| `cardBrandImages`object | Details about the card brand images. |
| `cardBrandImages.visa`string | The URL for the Visa card brand image. |
| `cardBrandImages.mastercard`string | The URL for the Mastercard card brand image. |
| `cardBrandImages.amex`string | The URL for the Amex card brand image. |
| `cardBrandImages.cup`string | The URL for the CUP card brand image. |
| `cardBrandImages.diners`string | The URL for the Diners card brand image. |
| `cardBrandImages.discover`string | The URL for the Discover card brand image. |
| `cardBrandImages.jcb`string | The URL for the JCB card brand image. |
| `isCvcRequired`boolean | Whether CVC is required. |
| `cvcComponentConfig`CardCvcComponentConfig | Details about the configuration for the card CVC component. See [Card CVC](/guides/components/web/card/card-cvc). |
| `cardSubmitComponentConfig`CardSubmitComponentConfig | Details about the configuration for the card submit component. See [Card submit](/guides/components/web/card/card-submit). |
| `hideCardBrandLogo`boolean | Whether to hide the card brand logo. |
| `submitButtonText`string | The text for the submit button. |
| `disableCardSelection`boolean | Whether to disable card selection. |
| `isRenderLastPurchaseCard`boolean | Whether to render the last card that was used for a purchase. |
| `isRenderLastPayoutCard`boolean | Whether to render the last card that was used for a payout. |
| `class`string | The class name for the component. |
| `selectTokenItemClass`string | The class name for the select token item in the select token list. |
| `useTransparentCardBrandImage`boolean | Whether to use transparent card brand images. Defaults to `true`. |
| `selectCardButtonAriaLabel`string | The aria label for the select card button. |
| `label`string | The label for the click-once component. |
| `labelAriaLabel`string | The aria label for the click-once component. |
| `submitAriaLabel`string | The aria label for the submit button. |
| `cardNumberAriaLabel`string | The aria label for the card number. |
| `cardExpiryDateAriaLabel`string | The aria label for the card expiry date. |
| `transactionInitiatorType`TransactionInitiatorType | The transaction initiator type. Determines whether the transaction is customer-initiated (CIT) or merchant-initiated (MIT). |
| `externalTokenId`string | External token identifier. Use this to specify a specific token to display when you have the token ID from an external system. |


The `cardSubmitComponentConfig` property accepts all card submit component configurations, including the `onCustomValidation` callback for validating merchant-owned fields alongside SDK component validation. See [Card submit](/guides/components/web/card/card-submit) for all available submit configuration options.

## Callbacks


```typescript
const clickOnceConfig: ClickOnceComponentConfig = {
  onCvcEntered: () => void,
  onOnceCardClick: () => void,
  onPreRenderTokens: (data: RetrieveCardTokensReponseSuccess) => CardTokenMapping[],
  onRetrieveTokensFailed: (error: BaseSdkException | RetrieveCardTokensReponseFailed | RetrieveCardTokenDetailsResponseFailed) => void,
  buttonBuilder: (elementIds: ClickOnceButtonBuilderElementIds) => string,
  selectTokenItemBuilder: (elementIds: ClickOnceSelectTokenBuilderElementIds) => string
};
```

| Callback | Description |
|  --- | --- |
| `onCvcEntered: () => void` | Event handler for when a card verification code is entered. |
| `onOnceCardClick: () => void` | Event handler for when a card is clicked. |
| `onPreRenderTokens: (data: RetrieveCardTokensReponseSuccess) => CardTokenMapping[]` | Callback to order or filter tokens before rendering. Receives the successful response from the token retrieval API and returns an array of transformed card token objects ready for display. |
| `onRetrieveTokensFailed: (error: BaseSdkException | RetrieveCardTokensReponseFailed | RetrieveCardTokenDetailsResponseFailed) => void` | Event handler for when token retrieval fails. Receives error details for handling and displaying appropriate error messages. |
| `buttonBuilder: (elementIds: ClickOnceButtonBuilderElementIds) => string` | Callback to build custom token item layout. Receives element IDs and returns an HTML string containing elements with those IDs for custom rendering. |
| `selectTokenItemBuilder: (elementIds: ClickOnceSelectTokenBuilderElementIds) => string` | Callback to build custom token label. Receives element IDs for the token and returns custom HTML for displaying the token selection item. |


For more information about callbacks, see [Events](/guides/components/web/card/events).

## Example


```typescript
const clickOnceConfig: ClickOnceComponentConfig = {
 limitTokens: 5,
  filterBy: {
    excludeExpiredTokens: true,
    schemes: ["Visa", "Mastercard"],
    fundingSource: "Credit",
    issuerCountryCode: "USA",
    ownerType: "Consumer"
  },
  orderBy: {
    expiryDate: { 
      direction: "asc",
      priority: 1
    },
    scheme: { 
      valuesOrder: ["Visa", "Mastercard", "Amex"],
      priority: 2
    },
    fundingSource: { 
      valuesOrder: ["Credit", "Debit"],
      priority: 3
    },
    ownerType: { 
      valuesOrder: ["Consumer", "Commercial"],
      priority: 4
    },
    issuerCountryCode: { 
      direction: "desc",
      priority: 5
    },
    lastUsageDate: { 
      direction: "desc",
      orderByField: "lastSuccessfulPurchaseDate",
      priority: 6
    }
  },
  cardBrandImages: {
    visaSrc: "https://example.com/visa.png",
    mastercardSrc: "https://example.com/mastercard.png",
    amexSrc: "https://example.com/amex.png",
    cupSrc: "https://example.com/cup.png",
    dinersSrc: "https://example.com/diners.png",
    discoverSrc: "https://example.com/discover.png",    
   jcbSrc: "https://example.com/jcb.png",
  },
  isCvcRequired: true,
  cvcComponentConfig: {
    required: true,
    label: "Security Code",
    applyMask: true,
    showMaskToggle: true,
    labelPosition: "left",
    errorMessage: "Please enter a valid security code",
    inputStyles: {
      base: {
        color: "#333",
        fontSize: "16px"
      }
    }
  },
  cardSubmitComponentConfig: {
    submitText: "Pay {amount} {currency}",
    avsRequest: true,
    billingAddressComponents: {
      billingAddressComponent: billingAddress
    },
    // Validate merchant fields alongside SDK billing address
    onCustomValidation: async () => {
      let isValid = true;
      
      const email = document.getElementById('email').value;
      const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
      if (!email || !emailRegex.test(email)) {
        showFieldError('email', 'Please enter a valid email address');
        isValid = false;
      }
      
      const termsAccepted = document.getElementById('terms-checkbox').checked;
      if (!termsAccepted) {
        showFieldError('terms', 'You must accept the terms and conditions');
        isValid = false;
      }
      
      return isValid;
    },
    onPreAuthorisation: async (data) => {
      return { psd2Data: {} };
    },
    onPostAuthorisation: (result) => {
      console.log('Payment completed:', result.merchantTransactionId);
      window.location.href = '/success';
    }
  },
  hideCardBrandLogo: false,
  submitButtonText: "Pay now",
  disableCardSelection: false,
  isRenderLastPurchaseCard: true,
  isRenderLastPayoutCard: true,
  transactionInitiatorType: TransactionInitiatorType.CIT,
  externalTokenId: "ext_token_123456789",
  onCvcEntered: () => {
    console.log('CVC has been entered');
  },
  onOnceCardClick: () => {
    console.log('Card was clicked');
  },
  onPreRenderTokens: (data) => {
    // Filter to only show tokens from USA issuers
    return data.gatewayTokens
      .filter((token) => token.issuerCountryCode === 'USA')
      .map((token) => ({
        id: token.gatewayTokenId,
        isCvcRequired: true
      }));
  },
  onRetrieveTokensFailed: (error) => {
    console.error('Failed to retrieve tokens:', error);
    showErrorMessage('Unable to load saved cards. Please try again.');
  },
  buttonBuilder: (elementIds) => {
    return `
      <div class="custom-token-layout">
        <div id="${elementIds.tokenImageId}" class="token-image"></div>
        <div id="${elementIds.tokenLabelId}" class="token-label"></div>
        <div id="${elementIds.cvcComponentId}" class="cvc-input"></div>
        <div id="${elementIds.payNowId}" class="pay-button"></div>
      </div>
    `;
  },
  selectTokenItemBuilder: (elementIds) => {
    return `
      <div class="custom-select-token">
        <div id="${elementIds.tokenImageId}" class="card-brand-image"></div>
        <div id="${elementIds.cardNumberId}" class="card-number"></div>
        <div id="${elementIds.expiryDateId}" class="expiry-date"></div>
      </div>
    `;
  }
};
```