npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@zenskar/ui-kit

v0.1.21

Published

Zenskar UI Kit for building customizable checkout experiences

Readme

Zenskar UI Kit

A React UI component library for building customizable checkout experiences and customer billing management.

What's New

See the CHANGELOG for latest updates, bug fixes, and migration guides.

Latest Updates (v0.1.21):

  • New: Custom font support with elementFonts prop - Load Google Fonts or custom fonts into payment forms
  • Support for both CSS stylesheet fonts (Google Fonts, Adobe Fonts) and custom font files
  • New TypeScript types: PaymentElementFonts, CssFontSource, CustomFontSource
  • Full documentation and examples for implementing custom fonts
  • Enhanced AddPaymentMethod customization with font loading

Previous Updates (v0.1.20):

  • New: AddPaymentMethod confirmParams prop for handling hidden billing fields
  • Support for programmatic billing data when UI fields are customized away
  • Enhanced Stripe integration for flexible payment form configurations

Previous Updates (v0.1.17-0.1.19):

  • New: Type-safe element retrieval with automatic type narrowing for getElement() method
  • New: AddPaymentMethod reset() method for clearing form and creating fresh SetupIntent
  • Improved TypeScript developer experience with full IntelliSense support
  • No more manual type assertions needed when working with elements
  • Fixed: PaymentElement types now resolve correctly in consumer IDEs instead of showing as any
  • New customer.contracts() and customer.contractById() methods
  • Payment method type control with paymentMethodTypes prop
  • Automatic locale detection with elementLocale prop (defaults to 'auto')
  • TypeScript type exports for AddPaymentMethod element
  • New PaymentHistory component (replaces TransactionHistory)
  • New customer.payments() method (replaces transactions())
  • Fixed AddPaymentMethod customization bugs
  • Improved type exports and documentation

Installation

npm install @zenskar/ui-kit

Available Components

The Zenskar UI Kit provides the following components:

  • BillingInformation - Component for displaying customer billing details and address information
  • PaymentMethods - Component for managing actions(e.g updating default payment method) and displaying payment methods including cards and bank accounts
  • InvoiceHistory - Component for displaying customer invoice history with filtering and sorting capabilities
  • PaymentHistory - Component for displaying payment history and financial activity tracking
  • ManageBillingInformation - Element for managing customer billing information with customizable fields and validation modes
  • AddPaymentMethod - Element for adding new payment methods

Provider & Hooks

  • ZenskarProvider - Required wrapper component that provides context to all library components
  • useZenskar - Hook to access Zenskar service methods for custom state management
  • useZenskarElements - Hook to access element instances for programmatic control
  • useCheckout - Hook to access checkout service methods for plan subscriptions

Importing Components

Tree-Shaked Imports (Recommended for optimal bundle size)

Import individual components from their dedicated entry points:

// Provider
import { ZenskarProvider } from '@zenskar/ui-kit/provider'

// Individual Components (import only what you need)
import { BillingInformation } from '@zenskar/ui-kit/BillingInformation'
import { PaymentMethods } from '@zenskar/ui-kit/PaymentMethods'
import { InvoiceHistory } from '@zenskar/ui-kit/InvoiceHistory'
import { PaymentHistory } from '@zenskar/ui-kit/PaymentHistory'
import { ManageBillingInformation } from '@zenskar/ui-kit/ManageBillingInformation'
import { AddPaymentMethod } from '@zenskar/ui-kit/AddPaymentMethodElement'

// Hooks
import { useZenskar, useZenskarElements } from '@zenskar/ui-kit/hooks'

// Types
import type { Customer, PaymentMethod, Invoice } from '@zenskar/ui-kit/types'

Barrel Import (Convenience import)

Import everything from the main entry point:

import { 
  // Provider (Required)
  ZenskarProvider,
  
  // Components
  BillingInformation,
  PaymentMethods,
  InvoiceHistory,
  PaymentHistory,
  ManageBillingInformation,
  AddPaymentMethod,
  
  // Hooks
  useZenskar,
  useZenskarElements
} from '@zenskar/ui-kit'

Bundle Optimization: Use tree-shaked imports for smaller bundle sizes. Each component is built as a separate entry point, allowing bundlers to include only the code you actually use.

Available Types

The Zenskar UI Kit exports comprehensive TypeScript types for better development experience:

Customer & Payment Types

import type {
  Customer,                    // Customer billing information and details
  PaymentMethod,              // Individual payment method (card, bank account)
  PaymentMethodsList,         // Paginated list of payment methods
} from '@zenskar/ui-kit'

Invoice & Payment Types

import type {
  Invoice,                    // Individual invoice data
  InvoicesList,              // Paginated list of invoices
  Payment,                   // Individual payment record
  PaymentsList,              // Paginated list of payments
} from '@zenskar/ui-kit'

Configuration & Provider Types

import type {
  ZenskarProviderProps,      // Props for ZenskarProvider component
  Theme,                     // Theme configuration for styling
  ServiceParams,             // Parameters for service method calls
} from '@zenskar/ui-kit'

Element Types

import type {
  ZenskarError,
  // AddPaymentMethod element types
  PaymentElementAppearance,
  PaymentElementOptions,
  PaymentElementLocale,
  PaymentElementFonts,
  CssFontSource,
  CustomFontSource,
  PaymentElementFormResult,
} from '@zenskar/ui-kit'

Checkout Types

import type {
  CreateCheckoutRequest,           // Request for creating checkout
  CheckoutResponse,                // Checkout session response
  CheckoutConfirmRequest,          // Request for confirming checkout
  ConfirmCheckoutResponse,         // Confirmation response with contract
  CheckoutEstimates,               // Invoice estimates (current & next)
  CheckoutStatus,                  // Checkout status enum
  ProductQuantityOverride,         // Quantity override for pricing
  ProductQuantityResponse,         // Product quantity in response
} from '@zenskar/ui-kit'

Service Methods

The Zenskar UI Kit provides service methods through the useZenskar hook for custom management. These methods work with any state management solution (useState, Zustand, React Query, SWR, etc.).

Available Service Methods

const zenskar = useZenskar()

// Customer service methods
const customerService = zenskar.customer

// Available methods:
await customerService.details()           // Get customer billing information
await customerService.paymentMethods()   // Get customer payment methods
await customerService.invoices(params)   // Get customer invoices with pagination
await customerService.payments(params)   // Get customer payment history with pagination
await customerService.contracts(params)  // Get customer contracts with pagination
await customerService.contractById(id)   // Get a specific contract by ID

Service Method Details

customerService.details()

Fetches customer billing information and details.

  • Returns: Promise<{ data: Customer }>
  • Usage: Get current customer information

customerService.paymentMethods()

Fetches all payment methods from the payment provider.

  • Returns: Promise<{ data: PaymentMethodsList }>
  • Usage: Display available payment methods

customerService.invoices(params)

Fetches paginated customer invoices with filtering.

  • Parameters: ServiceParams (limit, cursor sortKey, sortType)
  • Returns: Promise<{ data: InvoicesList }>
  • Usage: Display invoice history with pagination and sorting

customerService.payments(params)

Fetches paginated payment history.

  • Parameters: ServiceParams (limit, cursor, sortKey, sortType)
  • Returns: Promise<{ data: PaymentsList }>
  • Usage: Display payment history with pagination and sorting

customerService.contracts(params)

Fetches paginated customer contracts.

  • Parameters: ServiceParams (limit, cursor, sortKey, sortType)
  • Returns: Promise<{ data: ContractList }>
  • Usage: Display customer contracts with pagination and sorting

customerService.contractById(contractId)

Fetches a specific contract by ID.

  • Parameters: contractId (string, required)
  • Returns: Promise<{ data: Contract }>
  • Usage: Display detailed contract information

Checkout Service Methods

The useCheckout hook provides methods for creating and managing checkout sessions for plan subscriptions.

import { useCheckout } from '@zenskar/ui-kit'

const checkout = useCheckout()

// Available methods:
await checkout.createCheckout(request)      // Create new checkout session
await checkout.confirmCheckout(id, request) // Confirm and finalize checkout

checkout.createCheckout(request)

Creates a new checkout session for plan purchase.

  • Parameters: CreateCheckoutRequest (plan_id, start_date, optional fields)
  • Returns: Promise<{ data: CheckoutResponse }>
  • Usage: Initialize checkout flow with plan details and estimates

checkout.confirmCheckout(checkoutId, request)

Confirms and finalizes a checkout session, creating the contract.

  • Parameters: checkoutId (string, required), CheckoutConfirmRequest (optional payment_method_id)
  • Returns: Promise<{ data: ConfirmCheckoutResponse }>
  • Usage: Complete checkout and create customer contract

Service Usage Examples

React + TypeScript Example

import React, { useState, useEffect } from 'react'
import { useZenskar } from '@zenskar/ui-kit'
import type { Customer, InvoicesList, ZenskarError } from '@zenskar/ui-kit'

const CustomerDashboard = () => {
  const zenskar = useZenskar()
  const [customer, setCustomer] = useState<Customer | null>(null)
  const [invoices, setInvoices] = useState<InvoicesList | null>(null)
  const [loading, setLoading] = useState(false)
  const [error, setError] = useState<string | null>(null)

  useEffect(() => {
    const fetchData = async () => {
      setLoading(true)
      setError(null)
      
      try {
        // Fetch customer details
        const { data: customerData } = await zenskar.customer.details()
        setCustomer(customerData)
        
        // Fetch recent invoices
        const { data: invoicesData } = await zenskar.customer.invoices({ limit: 10 })
        setInvoices(invoicesData)
      } catch (err) {
        const zenskarError = err as ZenskarError
        setError(zenskarError.message)
      } finally {
        setLoading(false)
      }
    }

    fetchData()
  }, [])

  if (loading) return <div>Loading...</div>
  if (error) return <div>Error: {error}</div>

  return (
    <div>
      <h2>Customer: {customer?.customer_name}</h2>
      <p>Email: {customer?.email}</p>
      
      <h3>Recent Invoices ({invoices?.results?.length || 0})</h3>
      {invoices?.results?.map(invoice => (
        <div key={invoice.id}>
          {invoice.invoice_number} - ${invoice.invoice_total} ({invoice.status})
        </div>
      ))}
    </div>
  )
}

React Query Example

import { useQuery } from '@tanstack/react-query'
import { useZenskar } from '@zenskar/ui-kit'
import type { Customer, InvoicesList } from '@zenskar/ui-kit'

// Custom hooks
const useCustomerDetails = () => {
  const zenskar = useZenskar()
  return useQuery({
    queryKey: ['customer', 'details'],
    queryFn: async (): Promise<Customer> => {
      const { data } = await zenskar.customer.details()
      return data
    },
    staleTime: 5 * 60 * 1000, // 5 minutes
  })
}

const useCustomerInvoices = () => {
  const zenskar = useZenskar()
  return useQuery({
    queryKey: ['customer', 'invoices'],
    queryFn: async (): Promise<InvoicesList> => {
      const { data } = await zenskar.customer.invoices({ limit: 10 })
      return data
    },
    staleTime: 1 * 60 * 1000, // 1 minute
  })
}

// Component
const CustomerDashboardWithQuery = () => {
  const { data: customer, isLoading: customerLoading, error: customerError } = useCustomerDetails()
  const { data: invoices, isLoading: invoicesLoading, error: invoicesError } = useCustomerInvoices()

  if (customerLoading || invoicesLoading) return <div>Loading...</div>
  if (customerError || invoicesError) return <div>Error loading data</div>

  return (
    <div>
      <h2>Customer: {customer?.customer_name}</h2>
      <p>Email: {customer?.email}</p>
      
      <h3>Recent Invoices ({invoices?.results?.length || 0})</h3>
      {invoices?.results?.map(invoice => (
        <div key={invoice.id}>
          {invoice.invoice_number} - ${invoice.invoice_total} ({invoice.status})
        </div>
      ))}
    </div>
  )
}

Checkout Flow Example

import React, { useState } from 'react'
import { useCheckout } from '@zenskar/ui-kit'
import type { CheckoutResponse, ZenskarError } from '@zenskar/ui-kit'

const CheckoutFlow = ({ planId }: { planId: string }) => {
  const checkout = useCheckout()
  const [session, setSession] = useState<CheckoutResponse | null>(null)
  const [loading, setLoading] = useState(false)
  const [error, setError] = useState<string | null>(null)

  const handleCreateCheckout = async () => {
    setLoading(true)
    setError(null)

    try {
      // Create checkout session
      const { data } = await checkout.createCheckout({
        plan_id: planId,
        start_date: '2025-01-01',
        success_url: 'https://example.com/success',
      })
      setSession(data)
    } catch (err) {
      const zenskarError = err as ZenskarError
      setError(zenskarError.message)
    } finally {
      setLoading(false)
    }
  }

  const handleConfirmCheckout = async () => {
    if (!session) return
    setLoading(true)

    try {
      // Confirm checkout and create contract
      // Optional: Specify payment method ID from zenskar.customer.paymentMethods()
      // If omitted, uses customer's default payment method
      const { data } = await checkout.confirmCheckout(session.id, {
        payment_method_id: 'ea94efc5-ed4c-446c-9b8b-54cb1356e01c',
      })
      console.log('Contract created:', data.contract_id)
    } catch (err) {
      const zenskarError = err as ZenskarError
      setError(zenskarError.message)
    } finally {
      setLoading(false)
    }
  }

  if (error) return <div>Error: {error}</div>

  return (
    <div>
      {!session ? (
        <button onClick={handleCreateCheckout} disabled={loading}>
          {loading ? 'Creating...' : 'Start Checkout'}
        </button>
      ) : (
        <div>
          <p>Checkout Status: {session.checkout_status}</p>
          <button onClick={handleConfirmCheckout} disabled={loading}>
            {loading ? 'Confirming...' : 'Confirm Purchase'}
          </button>
        </div>
      )}
    </div>
  )
}

AddPaymentMethod Element Example

import React, { useState } from 'react'
import { AddPaymentMethod, useZenskar, useZenskarElements } from '@zenskar/ui-kit'

const AddPaymentExample = () => {
  const zenskar = useZenskar()
  const elements = useZenskarElements()
  const [loading, setLoading] = useState(false)

  const addPaymentElement = elements?.getElement('add-payment-method')

  const handleConfirm = async () => {
    if (!elements || !zenskar) return
    setLoading(true)

    try {
      const { data, error } = await zenskar.addPaymentMethod()
      if (error) {
        console.error('Payment method error:', error)
      } else {
        console.log('Payment method added successfully!')
        // Handle success - navigate, refresh data, etc.
      }
    } catch (err) {
      console.error('An unexpected error occurred:', err)
    } finally {
      setLoading(false)
    }
  }

  const handleCancel = () => {
    addPaymentElement?.clear()
  }

  return (
    <div className="max-w-md mx-auto p-6 space-y-6">
      <h2 className="text-2xl font-bold">Add Payment Method</h2>
      
      <AddPaymentMethod onReady={() => console.log('Payment form ready')} />
      
      <div className="flex gap-2">
        <button
          onClick={handleConfirm}
          disabled={loading}
          className="flex-1 bg-blue-600 text-white px-4 py-2 rounded hover:bg-blue-700 disabled:opacity-50"
        >
          {loading ? 'Adding...' : 'Confirm'}
        </button>
        
        <button
          onClick={handleCancel}
          disabled={loading}
          className="flex-1 bg-gray-200 text-gray-800 px-4 py-2 rounded hover:bg-gray-300"
        >
          Cancel
        </button>
      </div>
    </div>
  )
}

Type-Safe Element Retrieval (New in v0.1.17)

The useZenskarElements() hook now provides automatic TypeScript type narrowing for element instances, eliminating the need for manual type assertions.

import { useZenskarElements } from '@zenskar/ui-kit'

const MyComponent = () => {
  const elements = useZenskarElements()

  // ✅ Automatic type narrowing - TypeScript knows the exact type!
  const addPaymentElement = elements?.getElement('add-payment-method')
  // Type: AddPaymentMethodElementInstance | null

  if (addPaymentElement) {
    // Full IntelliSense support - no type casting needed
    await addPaymentElement.submit()    // ✅ TypeScript knows this exists
    addPaymentElement.reset()           // ✅ TypeScript knows this exists
    const isEmpty = addPaymentElement.isEmpty  // ✅ TypeScript knows this exists
  }

  // Works for all element types
  const billingElement = elements?.getElement('manage-billing-information')
  // Type: ManageBillingInformationElementInstance | null

  if (billingElement) {
    const data = billingElement.getValue()  // ✅ TypeScript knows this exists
    await billingElement.validate()         // ✅ TypeScript knows this exists
  }

  return <div>...</div>
}

Benefits:

  • ✅ No more as AddPaymentMethodElementInstance type assertions
  • ✅ Full IntelliSense auto-completion for element-specific methods
  • ✅ Compile-time type checking catches errors immediately
  • ✅ Better developer experience with zero runtime impact

AddPaymentMethod reset() Method (New in v0.1.17)

The AddPaymentMethod element includes a reset() method that creates a fresh SetupIntent and clears the payment form. This is particularly useful after successful payment submission when you want to allow users to add another payment method without remounting the component.

import React, { useState } from 'react'
import { AddPaymentMethod, useZenskar, useZenskarElements } from '@zenskar/ui-kit'

const AddMultiplePaymentMethods = () => {
  const zenskar = useZenskar()
  const elements = useZenskarElements()
  const [loading, setLoading] = useState(false)
  const [successMessage, setSuccessMessage] = useState('')

  const addPaymentElement = elements?.getElement('add-payment-method')

  const handleAddPayment = async () => {
    if (!zenskar || !addPaymentElement) return
    setLoading(true)

    try {
      const { data, error } = await zenskar.addPaymentMethod()
      if (error) {
        console.error('Payment method error:', error)
      } else {
        setSuccessMessage('Payment method added successfully!')

        // ✅ Reset the form to allow adding another payment method
        // This creates a new SetupIntent and clears all payment data
        addPaymentElement.reset()

        // Clear success message after 3 seconds
        setTimeout(() => setSuccessMessage(''), 3000)
      }
    } catch (err) {
      console.error('An unexpected error occurred:', err)
    } finally {
      setLoading(false)
    }
  }

  return (
    <div className="max-w-md mx-auto p-6 space-y-4">
      <h2 className="text-2xl font-bold">Add Payment Methods</h2>

      {successMessage && (
        <div className="p-3 bg-green-100 text-green-800 rounded">
          {successMessage}
        </div>
      )}

      <AddPaymentMethod />

      <button
        onClick={handleAddPayment}
        disabled={loading}
        className="w-full bg-blue-600 text-white px-4 py-2 rounded hover:bg-blue-700"
      >
        {loading ? 'Adding...' : 'Add Payment Method'}
      </button>

      <p className="text-sm text-gray-600">
        You can add multiple payment methods. The form will reset after each successful addition.
      </p>
    </div>
  )
}

Use cases for reset():

  • ✅ Allow users to add multiple payment methods in succession
  • ✅ Clear sensitive payment data after successful submission
  • ✅ Refresh the form without unmounting/remounting the component
  • ✅ Provide better UX for "Add Another Payment Method" workflows
  • ✅ Reset form state after errors to allow retry with fresh data

Without reset(): You would need to unmount and remount the entire AddPaymentMethod component, causing unnecessary re-renders and API calls.

With reset(): The form instantly clears and creates a new SetupIntent, providing a seamless experience for adding multiple payment methods.

ManageBillingInformation Element Example

Important Note: To display existing customer billing details, you must pass defaultValues in the options prop. You can get the customer data using zenskar.customerData from the useZenskar hook.

import React, { useState } from 'react'
import { ManageBillingInformation, useZenskar, useZenskarElements } from '@zenskar/ui-kit'

const ManageBillingExample = () => {
  const zenskar = useZenskar()
  const elements = useZenskarElements()
  const [loading, setLoading] = useState(false)

  // Get the element instance for control
  const manageBillingElement = elements?.getElement('manage-billing-information')

  // Get customer data from useZenskar hook - this is REQUIRED to show existing customer billing details
  const customerData = zenskar.customerData // Direct access to customer data

  const handleSave = async () => {
    if (!manageBillingElement || !zenskar) return
    setLoading(true)

    try {
      // Validate form first
      const isValid = await manageBillingElement.validate()
      if (!isValid) {
        console.error('Form validation failed')
        return
      }

      const { data, error } = await zenskar.updateBillingInformation()
      if (error) {
        console.error('Update error:', error)
      } else {
        console.log('Billing information updated successfully!')
        // Handle success - show toast, navigate, etc.
      }
    } catch (err) {
      console.error('An unexpected error occurred:', err)
    } finally {
      setLoading(false)
    }
  }

  const handleReset = () => {
    manageBillingElement?.clear()
  }

  return (
    <div className="max-w-2xl mx-auto p-6 space-y-6">
      <h2 className="text-2xl font-bold">Manage Billing Information</h2>
      
      {/* The Element with options */}
      <ManageBillingInformation
        options={{
          defaultValues: customerData, // Customer data from useZenskar hook
          fields: ['email', 'address', 'ship_to_address', 'tax_info'], // Optional: control which fields to show
          validationMode: 'onChange' // Optional: 'onChange' | 'onBlur' | 'onSubmit'
        }}
        onReady={() => console.log('Billing form ready')}
      />
      
      {/* Action Buttons */}
      <div className="flex gap-2">
        <button
          onClick={handleSave}
          disabled={loading || !manageBillingElement?.isValid || !manageBillingElement?.isReady}
          className="flex-1 bg-blue-600 text-white px-4 py-2 rounded hover:bg-blue-700 disabled:opacity-50"
        >
          {loading ? 'Saving...' : 'Save Changes'}
        </button>
        
        <button
          onClick={handleReset}
          disabled={loading}
          className="flex-1 bg-gray-200 text-gray-800 px-4 py-2 rounded hover:bg-gray-300"
        >
          Reset Form
        </button>
      </div>
    </div>
  )
}

AddPaymentMethod Element Customization

The AddPaymentMethod element uses Stripe's secure, PCI-compliant payment elements to collect payment method information. Through the elementOptions and elementAppearance props, you can customize the payment form fields, styling, and behavior to match your application's design.

Stripe Elements Integration

We leverage Stripe's proven payment infrastructure which provides:

  • PCI Compliance - Secure payment data collection without PCI burden on your application
  • Multiple Payment Types - Support for cards, bank accounts, and various regional payment methods
  • Customizable UI - Full control over styling and form fields through Stripe's Element options

Available Props

elementOptions

Configure which payment fields are displayed and their behavior.

elementAppearance

Customize the visual styling of the payment form elements.

confirmParams

Optional parameters for Stripe's payment confirmation. Use this when you've hidden billing fields from the UI but need to provide them programmatically (e.g., when hiding the country field, you must provide the country via confirmParams).

elementLocale

Control the language of payment form labels and error messages. Defaults to 'auto' for automatic detection.

elementFonts

Load custom fonts for the payment form using CSS stylesheets or custom font files.

Customization Examples

Basic Styling Customization

import { AddPaymentMethod } from '@zenskar/ui-kit'

const PaymentFormWithCustomStyling = () => {
  return (
    <AddPaymentMethod
      elementAppearance={{
        theme: 'stripe', // 'stripe' | 'night' | 'flat'
        variables: {
          colorPrimary: '#0570de',
          colorBackground: '#ffffff',
          colorText: '#30313d',
          colorDanger: '#df1b41',
          fontFamily: 'Ideal Sans, system-ui, sans-serif',
          spacingUnit: '2px',
          borderRadius: '4px',
          // Add more design tokens as needed
        },
        rules: {
          '.Input': {
            backgroundColor: '#f6f9fc',
            border: '1px solid #e6ebf1',
          },
          '.Input:focus': {
            border: '1px solid #0570de',
            boxShadow: '0 0 0 2px rgba(5, 112, 222, 0.2)',
          },
          '.Label': {
            color: '#6b7c93',
            fontWeight: '500',
            fontSize: '13px',
          },
        },
      }}
      onReady={() => console.log('Custom styled payment form ready')}
    />
  )
}

Advanced Field Configuration

import { AddPaymentMethod } from '@zenskar/ui-kit'

const PaymentFormWithCustomFields = () => {
  return (
    <AddPaymentMethod
      elementOptions={{
        layout: {
          type: 'tabs', // 'tabs' | 'accordion'
          defaultCollapsed: false,
          radios: false,
          spacedAccordionItems: true,
        },
        fields: {
          billingDetails: {
            name: 'auto', // 'auto' | 'never'
            email: 'auto',
            phone: 'never',
            address: {
              country: 'auto',
              line1: 'auto',
              line2: 'never',
              city: 'auto',
              state: 'auto',
              postalCode: 'auto',
            },
          },
        },
        terms: {
          card: 'never', // 'auto' | 'always' | 'never'
          bancontact: 'never',
          ideal: 'never',
          sepaDebit: 'auto',
          usBankAccount: 'auto',
        },
      }}
      elementAppearance={{
        theme: 'stripe',
        variables: {
          fontFamily: 'system-ui, sans-serif',
          colorPrimary: '#635bff',
        },
      }}
      onReady={() => console.log('Payment form with custom fields ready')}
    />
  )
}

Dark Theme Example

import { AddPaymentMethod } from '@zenskar/ui-kit'

const DarkThemePaymentForm = () => {
  return (
    <AddPaymentMethod
      elementAppearance={{
        theme: 'night', // Built-in dark theme
        variables: {
          colorPrimary: '#635bff',
          colorBackground: '#1a1a1a',
          colorText: '#ffffff',
          colorDanger: '#fa755a',
          borderRadius: '8px',
        },
        rules: {
          '.Input': {
            backgroundColor: '#2d2d2d',
            border: '1px solid #404040',
            color: '#ffffff',
          },
          '.Input:focus': {
            border: '1px solid #635bff',
            boxShadow: '0 0 0 2px rgba(99, 91, 255, 0.3)',
          },
          '.Label': {
            color: '#b4b4b4',
          },
        },
      }}
      onReady={() => console.log('Dark theme payment form ready')}
    />
  )
}

Minimal Fields Configuration

import { AddPaymentMethod } from '@zenskar/ui-kit'

const MinimalPaymentForm = () => {
  return (
    <AddPaymentMethod
      elementOptions={{
        fields: {
          billingDetails: {
            name: 'never',
            email: 'never',
            phone: 'never',
            address: 'never',
          },
        },
        layout: {
          type: 'accordion',
          defaultCollapsed: false,
          radios: true,
          spacedAccordionItems: false,
        },
      }}
      elementAppearance={{
        theme: 'flat',
        variables: {
          colorPrimary: '#000000',
          borderRadius: '0px',
          fontFamily: 'monospace',
        },
      }}
      onReady={() => console.log('Minimal payment form ready')}
    />
  )
}

Hidden Billing Fields with confirmParams

When you customize the payment form to hide certain billing fields (like country), you can provide that information programmatically using the confirmParams prop:

import { AddPaymentMethod } from '@zenskar/ui-kit'

const PaymentFormWithHiddenCountry = () => {
  return (
    <AddPaymentMethod
      elementOptions={{
        fields: {
          billingDetails: {
            address: {
              country: 'never', // Hide country field from UI
            },
          },
        },
      }}
      confirmParams={{
        payment_method_data: {
          billing_details: {
            address: {
              country: 'US', // Provide country programmatically
            },
          },
        },
      }}
      onReady={() => console.log('Payment form ready')}
    />
  )
}

This is useful when you want to:

  • Simplify the payment form by hiding fields you already know
  • Set billing information based on user account data or location
  • Create a streamlined checkout experience

Payment Method Type Control

Control which payment methods are available in the form using the paymentMethodTypes prop:

import { AddPaymentMethod } from '@zenskar/ui-kit'

// Card payments only (skips organization config fetch)
const CardOnlyPaymentForm = () => {
  return (
    <AddPaymentMethod
      paymentMethodTypes={['card']}
      onReady={() => console.log('Card payment form ready')}
    />
  )
}

// Both card and US bank account
const MultiPaymentForm = () => {
  return (
    <AddPaymentMethod
      paymentMethodTypes={['card', 'us_bank_account']}
      onReady={() => console.log('Multi-payment form ready')}
    />
  )
}

// Use organization config (default behavior)
const DefaultPaymentForm = () => {
  return <AddPaymentMethod />
}

Behavior:

  • If paymentMethodTypes is provided with values: Uses these types directly, skips organization config fetch
  • If paymentMethodTypes is empty array [] or not provided: Fetches payment types from organization config
  • If invalid types are provided: Logs error to console and filters to supported types only
  • Supported types: 'card', 'us_bank_account'

Localization Support

Control the language of payment form labels and error messages using the elementLocale prop:

import { AddPaymentMethod } from '@zenskar/ui-kit'

// Automatic language detection (default)
const AutoLocaleForm = () => {
  return <AddPaymentMethod elementLocale="auto" />
}

// Spanish
const SpanishForm = () => {
  return <AddPaymentMethod elementLocale="es" />
}

// French
const FrenchForm = () => {
  return <AddPaymentMethod elementLocale="fr" />
}

// German
const GermanForm = () => {
  return <AddPaymentMethod elementLocale="de" />
}

Supported locales: 'auto' (default), 'en', 'es', 'fr', 'de', 'ja', 'zh', and many more.

Custom Fonts Support

Load custom fonts into the payment form using the elementFonts prop. This accepts both CSS stylesheet URLs (like Google Fonts) and custom font file URLs.

Using CSS Fonts (Google Fonts, Adobe Fonts, etc.)

import { AddPaymentMethod } from '@zenskar/ui-kit'

const PaymentFormWithGoogleFonts = () => {
  return (
    <AddPaymentMethod
      elementFonts={[
        {
          cssSrc: 'https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600;700&display=swap'
        }
      ]}
      elementAppearance={{
        variables: {
          fontFamily: 'Poppins, sans-serif',
        }
      }}
      onReady={() => console.log('Payment form with custom font ready')}
    />
  )
}

Using Custom Font Files

import { AddPaymentMethod } from '@zenskar/ui-kit'

const PaymentFormWithCustomFont = () => {
  return (
    <AddPaymentMethod
      elementFonts={[
        {
          family: 'Avenir',
          src: 'url(https://my-domain.com/assets/avenir.woff)',
          weight: '500',
        }
      ]}
      elementAppearance={{
        variables: {
          fontFamily: 'Avenir, sans-serif',
        }
      }}
      onReady={() => console.log('Payment form with custom font ready')}
    />
  )
}

Using Multiple Font Sources

import { AddPaymentMethod } from '@zenskar/ui-kit'

const PaymentFormWithMultipleFonts = () => {
  return (
    <AddPaymentMethod
      elementFonts={[
        // Load from CSS stylesheet
        {
          cssSrc: 'https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap'
        },
        // Load custom font file
        {
          family: 'CustomFont',
          src: 'url(https://example.com/fonts/custom.woff2)',
          weight: '400',
          display: 'swap'
        }
      ]}
      elementAppearance={{
        variables: {
          fontFamily: 'Roboto, CustomFont, sans-serif',
        }
      }}
      onReady={() => console.log('Payment form with multiple fonts ready')}
    />
  )
}

Font Configuration Options:

For CSS fonts (cssSrc):

  • cssSrc: URL of the CSS stylesheet containing font definitions

For custom fonts:

  • family: CSS font-family name (required)
  • src: URL of the font file in CSS url() format (required)
  • weight: Font weight (e.g., '400', '500', '700', 'bold')
  • style: Font style (e.g., 'normal', 'italic', 'oblique')
  • display: Font display strategy (e.g., 'auto', 'swap', 'fallback')
  • unicodeRange: Unicode range the font supports

Note: After loading fonts with elementFonts, remember to apply them using elementAppearance.variables.fontFamily.

TypeScript Type Exports

Import TypeScript types for type-safe configuration:

import type {
  PaymentElementAppearance,
  PaymentElementOptions,
  PaymentElementLocale,
  PaymentElementFonts,
  CssFontSource,
  CustomFontSource,
  PaymentElementFormResult,
} from '@zenskar/ui-kit'

// Type-safe appearance configuration
const appearance: PaymentElementAppearance = {
  theme: 'night',
  variables: {
    colorPrimary: '#635bff',
    colorBackground: '#1a1a1a',
    colorText: '#ffffff',
    borderRadius: '8px',
  },
  rules: {
    '.Input': {
      backgroundColor: '#2d2d2d',
      border: '1px solid #404040',
    },
  },
}

// Type-safe element options
const options: PaymentElementOptions = {
  layout: {
    type: 'tabs',
    defaultCollapsed: false,
  },
  fields: {
    billingDetails: {
      name: 'auto',
      email: 'auto',
      phone: 'never',
    },
  },
}

// Type-safe locale
const locale: PaymentElementLocale = 'fr'

// Type-safe fonts
const fonts: PaymentElementFonts = [
  { cssSrc: 'https://fonts.googleapis.com/css2?family=Poppins:wght@400;600&display=swap' },
  {
    family: 'CustomFont',
    src: 'url(https://example.com/fonts/custom.woff2)',
    weight: '400'
  }
]

// Use in component
const TypeSafePaymentForm = () => {
  return (
    <AddPaymentMethod
      elementAppearance={appearance}
      elementOptions={options}
      elementLocale={locale}
      elementFonts={fonts}
    />
  )
}

Stripe Elements Documentation

For complete customization options, refer to:

Security & Compliance

  • All payment data is processed directly by Stripe's secure servers
  • Zenskar never handles raw payment card data
  • Automatic PCI compliance when using Stripe Elements
  • Built-in fraud detection and 3D Secure support

Importing Styles

Import the CSS styles in your application:

import '@zenskar/ui-kit/styles'

Troubleshooting Style Imports

If you're getting errors when importing styles, add the following declarations to your global.d.ts or vite-env.d.ts file (if you are using Vite):

// Declare style module
declare module "@zenskar/ui-kit/styles" {
  export {};
}

// Optional: If your project complains about CSS imports elsewhere
declare module "*.css";

ZenskarProvider Usage Example

✅ Correct Usage (Required)

import '@zenskar/ui-kit/styles'
import { ZenskarProvider, BillingInformation, PaymentHistory } from '@zenskar/ui-kit'

function App() {
  return (
    <ZenskarProvider
      organisationId="your-org-id"
      customerId="customer-123"
      token="your-auth-token"
      theme={customTheme}
    >
      <BillingInformation />
      <PaymentHistory />
    </ZenskarProvider>
  )
}

❌ Incorrect Usage (Will Show Error)

Missing ZenskarProvider

// This will show error: "Component must be wrapped with ZenskarProvider"
<BillingInformation />
<PaymentHistory />

Missing Organisation ID or Customer ID

// This will show error: "Organisation ID is required"
<ZenskarProvider customerId="customer-123">
  <BillingInformation />
</ZenskarProvider>