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

stripe-pwa-elements

v4.0.3

Published

Framework-agnostic Stripe Payment Elements as Web Components

Readme

npm version CI license npm downloads Built With Stencil

stripe-pwa-elements

Framework-agnostic Stripe payment components built with Web Components. Works with any web framework — React, Vue, Angular, Svelte, or plain HTML.

Note: The current npm package is stripe-pwa-elements (this repo). The old package @stripe-elements/stripe-elements (v2.0.2) is deprecated and superseded — please use stripe-pwa-elements instead.

Try it first

Edit in CodeSandbox

Open the live demo in CodeSandbox (Stripe test mode, no setup or API keys needed) before installing anything. The demo covers:

  • <stripe-card-element> — card number / expiry / CVC with a PaymentIntent confirm flow
  • <stripe-address-element> — billing address form
  • <stripe-express-checkout-element> — Apple Pay / Google Pay / Link (device-dependent)

There is no <stripe-payment-element> demo yet. See examples/codesandbox for details.

Used in production

capacitor-community/stripe

This library powers the Web implementation of @capacitor-community/stripe, which receives 4,000+ weekly downloads. If you use Capacitor for cross-platform apps, stripe-pwa-elements handles all Stripe UI on the web layer.

Manual follow-up (external repo): Add a reciprocal link in the capacitor-community/stripe README pointing back to this package.

Why stripe-pwa-elements?

Integrating Stripe from scratch requires wiring up several moving parts. This library collapses all of that into a single HTML element.

Before — raw @stripe/stripe-js (≈ 40 lines)

<div id="payment-element"></div>
<button id="pay" disabled>Pay</button>

<script type="module">
  import { loadStripe } from 'https://esm.sh/@stripe/stripe-js';

  // 1. Load Stripe.js
  const stripe = await loadStripe('pk_test_xxxxx');

  // 2. Create an Elements instance with your PaymentIntent client secret
  const elements = stripe.elements({
    clientSecret: 'pi_xxxxx_secret_xxxxx',
  });

  // 3. Create and mount the Payment Element
  const paymentElement = elements.create('payment');
  paymentElement.mount('#payment-element');

  // 4. Enable the button once the element is ready
  paymentElement.on('ready', () => {
    document.getElementById('pay').disabled = false;
  });

  // 5. Handle form submission
  document.getElementById('pay').addEventListener('click', async e => {
    e.preventDefault();

    // 6. Validate the payment details before confirming
    const { error: submitError } = await elements.submit();
    if (submitError) {
      console.error(submitError.message);
      return;
    }

    // 7. Confirm the payment (redirects on success)
    const { error } = await stripe.confirmPayment({
      elements,
      confirmParams: {
        return_url: window.location.href,
      },
    });

    if (error) {
      console.error(error.message);
    }
  });
</script>

After — stripe-pwa-elements (≈ 5 lines)

<!-- One CDN line registers the custom element -->
<script type="module" src="https://unpkg.com/stripe-pwa-elements/dist/stripe-elements/stripe-elements.esm.js"></script>

<!-- Drop in the element — Stripe.js loading, Elements creation, mounting,
     form submission, and confirmPayment are all handled for you -->
<stripe-payment-element
  publishable-key="pk_test_xxxxx"
  intent-client-secret="pi_xxxxx_secret_xxxxx"
></stripe-payment-element>

The component emits a defaultFormSubmitResult event when the payment completes, so you can react to success or failure without writing any Stripe boilerplate.

Value props

  • Framework-agnostic — Standard Web Components: drop into React, Vue, Angular, Svelte, or plain HTML with no adapter needed.
  • No build step — one CDN line — Load via <script type="module"> from unpkg; no npm, no bundler, no configuration required.
  • PCI DSS SAQ-A eligible — All card data is entered inside Stripe-hosted iframes. Your page never touches raw card numbers, keeping you in the lightest PCI self-assessment tier.

Trust signal

capacitor-community/stripe — 4000+ weekly downloads

Used in production as the web layer of @capacitor-community/stripe, which sees 4,000+ weekly npm downloads across Capacitor-powered iOS and Android apps.

Features

  • Framework-agnostic — Standard Web Components that work everywhere
  • Full Stripe Elements coverage — Card, Payment, Express Checkout, Address, and more
  • Multiple payment flows — PaymentIntent, SetupIntent, and Checkout Session
  • Apple Pay / Google Pay — Payment Request Button and Express Checkout support
  • Internationalization — Built-in i18n support (English, Japanese, Portuguese)
  • Lightweight — Minimal dependencies, lazy-loaded Stripe.js

Installation

npm install stripe-pwa-elements

Upgrading from Stripe.js 8

This package now uses Stripe.js 9 (Dahlia). Component methods and event names are unchanged, but Stripe objects exposed through events follow the Dahlia breaking changes:

  • Replace direct stripe.initCheckout() calls and StripeCheckout imports with initCheckoutElementsSdk() and StripeCheckoutElementsSdk. The component's initStripeWithCheckoutSession() handles this internally.
  • Handle the Promise returned by elements.update() and replace boolean layout.radios options with supported string values.
  • Replace legacy Sources/Intent methods (including createSource in older examples) with current Payment Methods/Intent APIs. Direct Embedded Checkout integrations must use createEmbeddedCheckoutPage().
  • The Address component explicitly requests localized values to preserve its existing getValue() and submit results. Raw Stripe Address Element change events now return Latin-formatted address.state values.
  • If you load Stripe.js manually, use https://js.stripe.com/dahlia/stripe.js and align other Stripe.js dependencies to v9. Server API versions are managed separately; on Dahlia, this component's Checkout Sessions use ui_mode: 'elements'.

Script tag

<script type="module" src="https://unpkg.com/stripe-pwa-elements/dist/stripe-elements/stripe-elements.esm.js"></script>

ES Module

import { defineCustomElements } from 'stripe-pwa-elements/loader';
defineCustomElements();

Bundlers (Vite, webpack, Capacitor)

When using a bundler — including Capacitor apps built with Vite — import the components you need directly from the custom-elements build. Each module auto-registers its element on import, so no defineCustomElements() call is needed:

import 'stripe-pwa-elements/dist/components/stripe-payment-element';

This avoids the runtime dynamic import the lazy loader relies on, which can fail with Failed to fetch dynamically imported module under Vite. See the Bundler Integration guide for Vite/webpack/Rollup and Capacitor setup examples.

Components

<stripe-card-element>

Stripe Card form with split fields (card number, expiry, CVC).

Documentation

<stripe-payment-element>

Unified payment form supporting multiple payment methods.

Documentation

<stripe-express-checkout-element>

Express Checkout with Apple Pay, Google Pay, Link, and more.

Documentation

<stripe-payment-request-button>

(Beta) Payment Request API button (Apple Pay / Google Pay).

Documentation

<stripe-address-element>

Address collection form with autocomplete.

Documentation

<stripe-link-authentication-element>

Email collection with Stripe Link one-click checkout.

Documentation

<stripe-currency-selector>

Currency selection component.

Documentation

<stripe-modal>

Modal wrapper for payment components.

Documentation

<stripe-card-element-modal>

Combined Card Element with Modal wrapper.

Documentation

Quick Start

HTML

<stripe-card-element
  publishable-key="pk_test_xxxxx"
  intent-client-secret="pi_xxxxx_secret_xxxxx"
></stripe-card-element>

<script type="module" src="https://unpkg.com/stripe-pwa-elements/dist/stripe-elements/stripe-elements.esm.js"></script>
<script>
  customElements.whenDefined('stripe-card-element').then(() => {
    const element = document.querySelector('stripe-card-element');
    element.addEventListener('formSubmit', async ({ detail }) => {
      const { stripe, cardNumber } = detail;
      const result = await stripe.createPaymentMethod({
        type: 'card',
        card: cardNumber,
      });
      console.log(result);
      element.updateProgress('success');
    });
  });
</script>

React

import { defineCustomElements } from 'stripe-pwa-elements/loader';

defineCustomElements();

function PaymentForm() {
  const handleFormSubmit = (e) => {
    const { stripe, cardNumber } = e.detail;
    stripe.createPaymentMethod({ type: 'card', card: cardNumber });
  };

  return (
    <stripe-card-element
      publishable-key="pk_test_xxxxx"
      intent-client-secret="pi_xxxxx_secret_xxxxx"
      onFormSubmit={handleFormSubmit}
    />
  );
}

Vue

<template>
  <stripe-card-element
    publishable-key="pk_test_xxxxx"
    intent-client-secret="pi_xxxxx_secret_xxxxx"
    @formSubmit="handleFormSubmit"
  />
</template>

<script setup>
import { defineCustomElements } from 'stripe-pwa-elements/loader';

defineCustomElements();

const handleFormSubmit = (e) => {
  const { stripe, cardNumber } = e.detail;
  stripe.createPaymentMethod({ type: 'card', card: cardNumber });
};
</script>

Use with AI assistants

The documentation site publishes machine-readable plain-text files that AI coding assistants (Claude Code, Cursor, GitHub Copilot, etc.) can use to answer questions about this library without hallucinating outdated API details.

| File | Purpose | | --- | --- | | /llms.txt | Index — links to the full and compact documentation sets | | /llms-full.txt | Full API reference for all components | | /llms-small.txt | Compact version with non-essential content removed |

These files are generated automatically from the documentation source at build time using the starlight-llms-txt plugin and always reflect the latest published docs.

Examples

See the example/ directory for complete working examples:

Use with coding agents (Agent Skill)

This repo ships an Agent Skill that teaches coding agents how to integrate stripe-pwa-elements correctly — picking the right component, wiring the publishable key + client secret, handling the submit/confirm flow, and asking before anything that changes your Stripe account. The skill lives in plugins/stripe-pwa-elements/skills/stripe-pwa-elements/.

Install it with the skills CLI:

npx skills add hideokamoto/stripe-pwa-elements

Or, in Claude Code, install it as a plugin:

/plugin marketplace add hideokamoto/stripe-pwa-elements
/plugin install stripe-pwa-elements@stripe-pwa-elements

Once installed in Claude Code, the skill activates automatically when Claude detects you are working with the library, or you can invoke it explicitly with /stripe-pwa-elements:stripe-pwa-elements.

The documentation site also serves the skill over HTTP, built from the same file:

| URL | Purpose | | --- | --- | | /skill.md | The skill's SKILL.md | | /.well-known/agent-skills/index.json | Discovery index (Agent Skills Discovery RFC, draft v0.2.0) with a SHA-256 digest per skill | | /.well-known/agent-skills/stripe-pwa-elements/SKILL.md | The skill at the path the discovery index points to |

Contribution

Getting Started

npm install
npm start

To build the component for production, run:

npm run build

To run the unit tests for the components, run:

npm test

Real-browser checks against Stripe test mode

e2e/stripe/ holds Playwright checks that drive the built components in Chromium against the real Stripe.js, in Stripe test mode. They use the docs site's demo API (https://stripe-pwa-elements-docs.wp-kyoto.workers.dev/api) for the pk_test_ key and for new PaymentIntents, so no keys are needed. They need network access to js.stripe.com and to that API, so they are not part of CI.

pnpm run build                            # the harness serves www/build
pnpm exec playwright install chromium     # once, if Playwright has no Chromium yet
pnpm run test:e2e:stripe
  • The harness is served on http://localhost:4321, an origin the demo API allows. Set STRIPE_E2E_PORT only if the demo API allows that origin too.
  • To use an already installed Chromium, set PLAYWRIGHT_BROWSERS_PATH, or point STRIPE_E2E_CHROMIUM_PATH at the executable.
  • Traces and screenshots of failed tests go to test-reports/stripe-e2e/.
  • Type-check the suite with pnpm exec tsc -p e2e/stripe/tsconfig.json.

To add a check: add a scenario to e2e/stripe/*.pw.ts using PaymentSheetHarness (e2e/stripe/support/payment-sheet.ts) and the demo API helpers (e2e/stripe/support/demo-api.ts). Element options and attributes go through harness.mount({ publishableKey, clientSecret, options, attributes }). For a different page, add an HTML file to e2e/stripe/pages/ that exposes the same window.harness contract and open it with harness.goto('/e2e/<file>.html').

Keep the Agent Skill up to date

When you add, rename or remove a component, or change its props, events, methods or how it is loaded, update the Agent Skill in plugins/stripe-pwa-elements/skills/stripe-pwa-elements/ in the same pull request. src/agent-skill.unit.spec.ts fails when the skill's component tags, CDN bundle path or i18n languages no longer match the code.

Security & PCI DSS SAQ-A

Card data never passes through this library's DOM, JavaScript state, or network requests. All sensitive input fields (card number, expiry, CVC) are rendered inside Stripe-hosted iframes, meaning your page never has access to raw card data. This architecture keeps integrations eligible for the lightest PCI DSS self-assessment questionnaire: SAQ-A.

How iframe isolation works

Your page (your domain)
┌─────────────────────────────────────────────────────────┐
│  <stripe-card-element>                                  │
│  ┌───────────────────────────────────────────────────┐  │
│  │  <iframe src="https://js.stripe.com/...">         │  │
│  │  ┌─────────────────────────────────────────────┐  │  │
│  │  │  Card number  [____ ____ ____ ____]          │  │  │
│  │  │  Expiry       [MM/YY]  CVC  [___]            │  │  │
│  │  │                                              │  │  │
│  │  │  (Stripe's origin — cross-origin boundary)   │  │  │
│  │  └─────────────────────────────────────────────┘  │  │
│  └───────────────────────────────────────────────────┘  │
│                                                         │
│  Your JS can call stripe.confirmPayment() but           │
│  CANNOT read card values from the iframe.               │
└─────────────────────────────────────────────────────────┘
  • The browser's same-origin policy prevents any JavaScript on your page from reading input values inside Stripe's iframe.
  • Card data travels directly from the iframe to Stripe's servers over TLS — it never touches your application server.
  • This library only manages the mounting, styling, and event wiring of those iframes; it does not alter Stripe's security model.

For a complete explanation see Stripe's SAQ-A documentation.

For the vulnerability reporting channel and supply-chain notes (npm provenance), see SECURITY.md.


Sponsors

If stripe-pwa-elements saves you time, please consider sponsoring the lead maintainer:

Sponsor hideokamoto


Public API & TypeScript types

All user-facing TypeScript types are exported directly from the package root. Import them using the package name:

import type {
  FormSubmitEvent,
  FormSubmitHandler,
  StripeLoadedEvent,
  StripeDidLoadedHandler,
  ProgressStatus,
  IntentType,
  InitStripeOptions,
  LinkAuthenticationElementChangeEvent,
  LinkAuthenticationElementChangeHandler,
  CurrencySelectorChangeEvent,
  CurrencySelectorChangeHandler,
  DefaultFormSubmitResult,
} from 'stripe-pwa-elements';

The custom-elements entry stripe-pwa-elements/dist/components/<tag> is a supported import path for bundler-based setups (see Bundlers above). However, do not import from internal paths such as dist/types/interfaces. Those paths are implementation details and are not part of the public API — they may change without notice across any release.

Semver policy

All types exported from the package root (stripe-pwa-elements) are considered public API and follow Semantic Versioning. Within the ^3.0.0 range:

  • No breaking changes will be made to the shape of any publicly exported type.
  • New optional fields may be added to event objects without a major bump.
  • Removals or renames of exported types always require a new major version.

Maintainers

| Maintainer | GitHub | Social | | --- | --- | --- | | Hidetaka Okamoto | hideokamoto | @hide__dev | | Masaki Hirano | contiki9 | @maki_saki | | Masahiko Sakakibara | rdlabo | @rdlabo |

License

MIT