Files
2025-11-30 08:48:24 +08:00

14 KiB

Primer Web Components - Component Reference

Core Components

<primer-checkout>

The root component that initializes the Primer SDK and manages the checkout flow.

Required Attributes:

  • client-token - JWT token from backend client session

Optional Attributes:

  • custom-styles - JSON string of CSS custom properties
  • loader-disabled - Boolean to disable loading indicator

Properties (set via JavaScript):

  • options - SDK configuration object (locale, payment methods, etc.)

Example:

<primer-checkout client-token="eyJ0eXAiOiJKV1QiLCJhbGc...">
  <primer-main slot="main">
    <!-- Content -->
  </primer-main>
</primer-checkout>

<primer-main>

Container for checkout content with predefined slots for different states.

Slots:

  • payments - Main payment method selection area
  • checkout-complete - Success state content
  • checkout-failure - Error state content

Example:

<primer-main slot="main">
  <div slot="payments">
    <primer-payment-method type="PAYMENT_CARD"></primer-payment-method>
  </div>
  <div slot="checkout-complete">
    <h2>Payment Successful!</h2>
  </div>
</primer-main>

<primer-payment-method>

Displays a specific payment method.

Attributes:

  • type - Payment method type (PAYMENT_CARD, PAYPAL, APPLE_PAY, GOOGLE_PAY, etc.)
  • disabled - Boolean to disable the payment method

Example:

<primer-payment-method type="PAYMENT_CARD"></primer-payment-method>
<primer-payment-method type="PAYPAL"></primer-payment-method>
<primer-payment-method type="GOOGLE_PAY" disabled></primer-payment-method>

<primer-payment-method-container>

Declarative container for automatically rendering filtered payment methods.

Attributes:

  • include - Comma-separated list of payment method types to include
  • exclude - Comma-separated list of payment method types to exclude

Example:

<!-- Show only digital wallets -->
<primer-payment-method-container
  include="APPLE_PAY,GOOGLE_PAY"
></primer-payment-method-container>

<!-- Show everything except cards -->
<primer-payment-method-container
  exclude="PAYMENT_CARD"
></primer-payment-method-container>

Card Form Components

<primer-card-form>

Container for card payment inputs with built-in validation and state management.

Slots:

  • card-form-content - Custom content area for inputs

Example:

<primer-card-form>
  <div slot="card-form-content">
    <primer-input-card-number></primer-input-card-number>
    <primer-input-card-expiry></primer-input-card-expiry>
    <primer-input-cvv></primer-input-cvv>
    <primer-card-form-submit></primer-card-form-submit>
  </div>
</primer-card-form>

<primer-input-card-number>

Secure card number input field with automatic card type detection.

DOM Structure:

<primer-input-wrapper>
  <primer-input-label slot="label">Card Number</primer-input-label>
  <div slot="input">
    <!-- Secure iframe for card number -->
    <primer-card-network-selector></primer-card-network-selector>
  </div>
</primer-input-wrapper>

<primer-input-card-expiry>

Expiration date input with automatic formatting (MM/YY).

<primer-input-cvv>

CVV/security code input field.

<primer-input-card-holder-name>

Cardholder name text input (not in secure iframe).

<primer-card-form-submit>

Localized submit button for card forms.

<primer-billing-address>

Collects billing address information (SDK Core only).

Attributes:

  • Mode configuration (drop-in or custom layout)

Example:

<primer-card-form>
  <div slot="card-form-content">
    <primer-input-card-number></primer-input-card-number>
    <primer-billing-address></primer-billing-address>
    <primer-card-form-submit></primer-card-form-submit>
  </div>
</primer-card-form>

Base UI Components

<primer-input-wrapper>

Container that provides consistent styling for form inputs.

Attributes:

  • has-error - Boolean to show error state

Slots:

  • label - For primer-input-label
  • input - For primer-input or custom content
  • error - For primer-input-error

Example:

<primer-input-wrapper>
  <primer-input-label slot="label">Email</primer-input-label>
  <primer-input slot="input" type="email"></primer-input>
  <primer-input-error slot="error">Invalid email</primer-input-error>
</primer-input-wrapper>

<primer-input>

Standard input field with consistent styling.

Attributes:

  • Standard HTML input attributes: type, value, placeholder, disabled, required, etc.
  • name - For form data collection

Events:

  • input - Value changed
  • change - Value committed (blur/Enter)
  • focus - Input focused
  • blur - Input blurred
  • invalid - Validation failed

<primer-input-label>

Form label component.

Attributes:

  • for - ID of associated input
  • disabled - Boolean for disabled state

<primer-input-error>

Error message component.

Attributes:

  • for - ID of associated input
  • active - Boolean to show/hide error

<primer-button>

Styled button component.

Attributes:

  • variant - "primary" or "secondary"
  • buttonType - "button" or "submit"
  • disabled - Boolean

Example:

<primer-button variant="primary">Pay Now</primer-button>
<primer-button variant="secondary">Cancel</primer-button>

Utility Components

<primer-error-message-container>

Automatically displays payment processing errors.

Example:

<div slot="payments">
  <primer-payment-method type="PAYMENT_CARD"></primer-payment-method>
  <primer-error-message-container></primer-error-message-container>
</div>

<primer-vault-manager>

Displays saved payment methods when vault is enabled.

Requires:

  • Vault enabled in SDK options: {"vault": {"enabled": true}}

<primer-show-other-payments>

Manages visibility of alternative payment methods when vault is active.

Slots:

  • other-payments - Content shown when "Show other payments" is clicked

Events

Core Checkout Events

primer:ready

  • Fired when SDK initialization completes
  • Detail: PrimerJS instance with callbacks:
    • onPaymentSuccess - New in v0.7.0
    • onPaymentFailure - New in v0.7.0
    • onVaultedMethodsUpdate - New in v0.7.0
    • onPaymentStart, onPaymentPrepare
    • refreshSession(), getPaymentMethods()

Example:

checkout.addEventListener('primer:ready', (event) => {
  const primer = event.detail;

  // Set up callbacks
  primer.onPaymentSuccess = ({ paymentSummary, paymentMethodType }) => {
    console.log('Payment successful!');
  };

  primer.onPaymentFailure = ({ error, paymentMethodType }) => {
    console.error('Payment failed:', error.message);
  };
});

primer:state-change

  • Fired when checkout state changes
  • Detail: {isProcessing, isSuccessful, isLoading, primerJsError, paymentFailure}
  • Note: errorprimerJsError, failurepaymentFailure (v0.7.0)

Example:

checkout.addEventListener('primer:state-change', (event) => {
  const { isProcessing, isSuccessful, primerJsError, paymentFailure } =
    event.detail;
  if (primerJsError) {
    console.error('SDK error:', primerJsError);
  }
  if (paymentFailure) {
    console.error('Payment failed:', paymentFailure);
  }
});

primer:methods-update

  • Fired when available payment methods change
  • Detail: InitializedPayments instance with .toArray(), .get(), .size() methods
  • Note: Replaces primer-payment-methods-updated

Example:

checkout.addEventListener('primer:methods-update', (event) => {
  const methods = event.detail.toArray();
  console.log(`${methods.length} payment methods available`);

  // Get specific method
  const cardMethod = event.detail.get('PAYMENT_CARD');
});

Payment Lifecycle Events (New in v0.7.0)

primer:payment-start

  • Fired when payment processing begins
  • Detail: undefined

primer:payment-success

  • Fired when payment completes successfully
  • Detail: {paymentSummary, paymentMethodType, timestamp}
  • PaymentSummary is PII-filtered (safe for client-side)

Example:

checkout.addEventListener('primer:payment-success', (event) => {
  const { paymentSummary, paymentMethodType, timestamp } = event.detail;
  console.log(`✅ Payment successful via ${paymentMethodType}`);
  console.log(
    `Card: ${paymentSummary.network} ending in ${paymentSummary.last4Digits}`,
  );
  // Navigate to success page
});

primer:payment-failure

  • Fired when payment fails
  • Detail: {error: {code, message, diagnosticsId}, paymentSummary?, paymentMethodType, timestamp}

Example:

checkout.addEventListener('primer:payment-failure', (event) => {
  const { error, paymentMethodType } = event.detail;
  console.error(`❌ Payment failed: ${error.message}`);
  console.error(`Diagnostics ID: ${error.diagnosticsId}`);
  // Show error to user
});

Vault Events (New in v0.7.0)

primer:vault:methods-update

  • Fired when vaulted payment methods loaded/updated
  • Detail: {vaultedPayments, timestamp}
  • vaultedPayments API: .toArray(), .get(id), .size()

Example:

checkout.addEventListener('primer:vault:methods-update', (event) => {
  const { vaultedPayments } = event.detail;
  console.log(`${vaultedPayments.size()} saved payment methods`);

  vaultedPayments.toArray().forEach((method) => {
    console.log(
      `${method.paymentInstrumentType}: ${method.paymentInstrumentData.last4Digits}`,
    );
  });
});

Card Events

primer:card-network-change

  • Fired when card network detected
  • Detail: {detectedCardNetwork, selectableCardNetworks, isLoading}

Example:

cardForm.addEventListener('primer:card-network-change', (event) => {
  const { detectedCardNetwork, selectableCardNetworks } = event.detail;
  console.log(`Detected: ${detectedCardNetwork}`);
});

primer:card-success

  • Fired when card form submission succeeds
  • Detail: {result}

primer:card-error

  • Fired when card validation errors occur
  • Detail: {errors: InputValidationError[]}

primer:card-submit (Triggerable)

  • Dispatch this event to trigger card form submission programmatically
  • Detail: {source?: string}

Example:

// Trigger card form submission from external button
const cardForm = document.querySelector('primer-card-form');
cardForm.dispatchEvent(
  new CustomEvent('primer:card-submit', {
    detail: { source: 'external-button' },
  }),
);

SDK Options Structure

interface SDKOptions {
  // Core Options
  sdkCore?: boolean; // Default: true since v0.4.0
  locale?: string; // e.g., 'en-GB', 'fr-FR'
  merchantDomain?: string; // For Apple Pay domain validation
  disabledPayments?: boolean; // Disable all payment methods
  enabledPaymentMethods?: PaymentMethodType[]; // Filter which methods display

  // Card Options
  card?: {
    cardholderName?: {
      required?: boolean;
      visible?: boolean;
    };
  };

  // Apple Pay Options
  applePay?: {
    buttonType?:
      | 'buy'
      | 'donate'
      | 'plain'
      | 'checkout'
      | 'set-up'
      | 'book'
      | 'subscribe';
    buttonStyle?: 'black' | 'white' | 'white-outline';
    billingOptions?: {
      requiredBillingContactFields?: (
        | 'emailAddress'
        | 'name'
        | 'phoneNumber'
        | 'postalAddress'
        | 'phoneticName'
      )[];
    };
    shippingOptions?: {
      requiredShippingContactFields?: (
        | 'emailAddress'
        | 'name'
        | 'phoneNumber'
        | 'postalAddress'
        | 'phoneticName'
      )[];
      requireShippingMethod?: boolean;
    };
  };

  // Google Pay Options
  googlePay?: {
    buttonType?:
      | 'long'
      | 'short'
      | 'book'
      | 'buy'
      | 'checkout'
      | 'donate'
      | 'order'
      | 'pay'
      | 'plain'
      | 'subscribe';
    buttonColor?: 'default' | 'black' | 'white';
    buttonSizeMode?: 'fill' | 'static';
    captureBillingAddress?: boolean;
    emailRequired?: boolean;
    requireShippingMethod?: boolean;
  };

  // PayPal Options
  paypal?: {
    style?: {
      layout?: 'vertical' | 'horizontal';
      color?: 'gold' | 'blue' | 'silver' | 'white' | 'black';
      shape?: 'rect' | 'pill';
      height?: number; // 25-55
      label?: 'paypal' | 'checkout' | 'buynow' | 'pay' | 'installment';
      tagline?: boolean;
      borderRadius?: number; // 0-55
      disableMaxWidth?: boolean;
    };
    disableFunding?: string[]; // ['credit', 'card', 'paylater', etc.]
    enableFunding?: string[]; // ['venmo', etc.]
    vault?: boolean;
    buyerCountry?: string; // Sandbox only
    debug?: boolean;
  };

  // Klarna Options
  klarna?: {
    paymentFlow?: 'DEFAULT' | 'PREFER_VAULT';
    allowedPaymentCategories?: ('pay_now' | 'pay_later' | 'pay_over_time')[];
    buttonOptions?: {
      text?: string;
    };
  };

  // Vault Options
  vault?: {
    enabled?: boolean;
    showEmptyState?: boolean;
  };

  // Stripe Options
  stripe?: {
    mandateData?: {
      fullMandateText?: string;
      merchantName?: string;
    };
    publishableKey?: string;
  };

  // Submit Button Options
  submitButton?: {
    amountVisible?: boolean;
    useBuiltInButton?: boolean; // Set false for external buttons
  };
}

CSS Custom Properties

Brand Colors

  • --primer-color-brand - Primary brand color
  • --primer-color-loader - Loading indicator color
  • --primer-color-focus - Focus state color

Typography

  • --primer-typography-brand - Font family

Spacing & Sizing

  • --primer-space-base - Base spacing unit (default: 4px)
  • --primer-size-base - Base size unit (default: 4px)
  • --primer-radius-base - Border radius (default: 4px)

Theme-Specific Variables

.primer-light-theme {
  --primer-color-text-primary: var(--primer-color-gray-900);
  --primer-color-background-outlined-default: var(--primer-color-gray-000);
}

.primer-dark-theme {
  --primer-color-text-primary: var(--primer-color-gray-100);
  --primer-color-background-outlined-default: var(--primer-color-gray-800);
}

Usage Example

:root {
  --primer-color-brand: #2f98ff;
  --primer-radius-base: 8px;
  --primer-typography-brand: 'Inter, sans-serif';
}

/* Or apply to specific checkout */
primer-checkout {
  --primer-color-brand: #4a6cf7;
  --primer-radius-base: 4px;
}