# Primer Web Components - Component Reference ## Core Components ### `` 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:** ```html ``` ### `` 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:** ```html

Payment Successful!

``` ### `` 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:** ```html ``` ### `` 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:** ```html ``` ## Card Form Components ### `` Container for card payment inputs with built-in validation and state management. **Slots:** - `card-form-content` - Custom content area for inputs **Example:** ```html
``` ### `` Secure card number input field with automatic card type detection. **DOM Structure:** ```html Card Number
``` ### `` Expiration date input with automatic formatting (MM/YY). ### `` CVV/security code input field. ### `` Cardholder name text input (not in secure iframe). ### `` Localized submit button for card forms. ### `` Collects billing address information (SDK Core only). **Attributes:** - Mode configuration (drop-in or custom layout) **Example:** ```html
``` ## Base UI Components ### `` 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:** ```html Email Invalid email ``` ### `` 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 ### `` Form label component. **Attributes:** - `for` - ID of associated input - `disabled` - Boolean for disabled state ### `` Error message component. **Attributes:** - `for` - ID of associated input - `active` - Boolean to show/hide error ### `` Styled button component. **Attributes:** - `variant` - "primary" or "secondary" - `buttonType` - "button" or "submit" - `disabled` - Boolean **Example:** ```html Pay Now Cancel ``` ## Utility Components ### `` Automatically displays payment processing errors. **Example:** ```html
``` ### `` Displays saved payment methods when vault is enabled. **Requires:** - Vault enabled in SDK options: `{"vault": {"enabled": true}}` ### `` 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:** ```javascript 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: `error` → `primerJsError`, `failure` → `paymentFailure` (v0.7.0) **Example:** ```javascript 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:** ```javascript 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:** ```javascript 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:** ```javascript 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:** ```javascript 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:** ```javascript 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:** ```javascript // 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 ```typescript 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 ```css .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 ```css :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; } ```