vue-stripe: Stripe Elements and Checkout as Vue components
Stripe Elements and Checkout as Vue components
At a glance
- What is it?
- vue-stripe wraps Stripe.js 10 as Vue 3 and Vue 2.7 components and composables, with a provider, an elements container, and a Payment Element. It is an early v6 release maintained largely by one person.
- Who is it for?
- vue-stripe fits teams already on Vue who want Stripe payment forms without hand-rolling Stripe.js lifecycle code, and its MIT licence and full Stripe.js coverage make it a low friction choice. It is the wrong fit for a Nuxt or SSR project that cannot run the browser only components on the server, or for anyone who needs a v5 stable API, since v6 changed the surface and the migration guide is the first document to read.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 6 days ago.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What the provider and elements container actually do
The library's central idea is a nesting requirement rather than a set of props. A README example shows the shape of a typical page: VueStripeProvider wraps everything and takes the publishable key, and inside it VueStripeElements takes the client secret and holds the actual Stripe UI components, in this case VueStripePaymentElement plus your own button component. The provider sets up the shared context, the elements container mounts Stripe into it, and only then can a child component talk to Stripe.
That is why the README states that composables such as usePaymentIntent() read the Stripe context and must be called in a component rendered inside VueStripeElements. It is a constraint that bites when you refactor: moving a button out of the elements container breaks it, and the error surfaces as a missing context rather than a type error. The composables come in one variant per Stripe.js confirm method, plus separate ones for tokens, Financial Connections, Identity, and Checkout Sessions.
The coverage claim in the README is worth reading precisely. It states that every Stripe.js 10 element and method has a component or composable, and links a coverage page for the mapping. Coverage is a different property from stability, and the two are separated by the announcement section further down the page.
Stripe.js 10 and the Payment Element decide the floor
The requirements table in the README is short and strict. vue must satisfy ^2.7.0 || ^3.0.0, with the note that Vue 2.6 is not supported, and @stripe/stripe-js must be ^10.0.0. So this is a library that targets a specific generation of Stripe.js, not a general purpose Stripe wrapper you can point at whatever version your account currently uses.
Within that generation the surface is wide. The README lists Payment, Express Checkout, Address, Tax ID and Currency Selector among the Stripe.js 10 elements covered, plus Checkout Sessions with Elements. The Modern Elements entry highlights the Payment Element supporting 40 or more payment methods, and the Every Checkout entry covers Hosted Checkout, Embedded Checkout, Custom Checkout, and a Checkout Form that is still marked beta. The Appearance API is supported in full, which is what lets you restyle the embedded fields to match a design system.
The practical consequence is that your Stripe account and your tenant configuration determine which of these you can actually use. A component existing in the library does not mean the payment method is enabled for your merchant account. That boundary between library coverage and account capability is where integration surprises usually live.
Installing the package and importing the styles
Installation is a single npm command that installs the library and the Stripe.js runtime together, because the peer requirement on @stripe/stripe-js ^10.0.0 is not optional:
npm install @vue-stripe/vue-stripe@^6 @stripe/stripe-js@^10Then import the component styles once, for example in main.ts:
import '@vue-stripe/vue-stripe/style.css'That step is easy to skip and produces a page where the embedded fields render unstyled. The README puts the import right after the install command rather than burying it in a setup section, which is a reasonable hint about how often it gets forgotten.
If you are coming from v5, the README points to a migration guide at vuestripe.com/guide/migration-v6. For a library where the v6 release landed with a matching beta sequence in the same week, that guide is not optional reading. The versions are deliberately coupled: the library at ^6 requires Stripe.js at ^10, so a v5 application cannot take the newest package without also moving its Stripe.js dependency.
A working page and button, end to end
The README's basic example is worth reading end to end, because it shows the shape of a correct integration rather than a fragment. The page component supplies the publishable key and the client secret, and the comment on the client secret marks where it comes from:
<!-- CheckoutPage.vue -->
<template>
<VueStripeProvider :publishable-key="publishableKey">
<VueStripeElements :client-secret="clientSecret">
<VueStripePaymentElement />
<PayButton :client-secret="clientSecret" />
</VueStripeElements>
</VueStripeProvider>
</template>
<script setup lang="ts">
import { VueStripeProvider, VueStripeElements, VueStripePaymentElement } from '@vue-stripe/vue-stripe'
import PayButton from './PayButton.vue'
const publishableKey = 'pk_test_...'
const clientSecret = 'pi_..._secret_...' // from your server
</script>The button component is where the composable is used, and it is a separate file precisely because it must live inside the elements container:
<!-- PayButton.vue -->
<template>
<button :disabled="loading" @click="pay">Pay now</button>
<p v-if="error">{{ error }}</p>
</template>
<script setup lang="ts">
import { usePaymentIntent } from '@vue-stripe/vue-stripe'
const props = defineProps<{ clientSecret: string }>()
const { confirmPayment, loading, error } = usePaymentIntent()
const pay = () =>
confirmPayment({
clientSecret: props.clientSecret,
confirmParams: { return_url: `${window.location.origin}/complete` }
})
</script>Three details carry the design. The composable returns loading and error refs that the template binds to, so the component owns the UI state of the call. The client secret is passed as a prop as well as through context, because the composable needs it to confirm. And confirmParams sets a return_url, which is what tells Stripe where to send the customer when the payment needs a redirect.
The monorepo, the playground, and the test setup
The repository is organised as a monorepo using pnpm workspaces and Turborepo. The tree in the README shows packages/ holding vue-stripe, the main library, and vue2-smoke, which runs the built library under Vue 2.7 in CI. Under apps/ sit docs, a VitePress documentation site, playground, a development playground, and backend, a backend for that playground. A shared TypeScript configuration lives in tools/typescript-config.
The vue2-smoke package is the interesting one for anyone worried about the dual version claim. The README's feature list says one build serves both Vue 3 and Vue 2.7, tested on each in CI. A package whose only job is to run the built artefact under Vue 2.7 is how that claim gets checked continuously rather than asserted.
The root package.json shows the tooling that backs the testing claim. Tasks run through turbo: build, dev, test, lint, typecheck, docs:dev, docs:build. There is a script that seeds Stripe data, scripts/seed-stripe.sh, exposed through stripe:seed with clean, reset, and clean-only variants, and separate playground and backend dev tasks filtered by package name. The package manager is pinned to [email protected] through the packageManager field, and commit hooks run through husky with commitlint enforcing commit message format on pull requests.
For a library in early release, that harness matters more than it would for a mature one, because it is the machinery keeping the Vue 2.7 and Vue 3 paths honest while the API is still moving.
One maintainer, and an announcement that says so
The README contains an announcement section that deserves to be read rather than skimmed. It calls v6 an early release and warns that bugs may be present. It then adds a note on AI-assisted maintenance, stating that the maintainer decided to use AI to help maintain the project, that every change is reviewed, tested and verified by the human maintainer before shipping, and that the project is maintained largely by one person in limited spare time.
That is unusual candour in a README, and it is a maintenance signal rather than a marketing one. The repository is not archived and the last push was on 2026-10-15, the same day as the v6.0.0 release and the v6.0.0-beta.6 tag, with beta.5 the day before. So the project is moving quickly, which is a good sign for a recent rewrite, but the throughput depends on one person.
The licence is MIT, held in the LICENSE file at the top level, which is the permissive end of the scale for a component library you embed in a commercial product. Other repository files signal the seriousness of the setup: AGENTS.md and CLAUDE.md for agent instructions, CONTRIBUTING.md, CODE_OF_CONDUCT.md, knip.json for unused dependency checks, commitlint.config.js, eslint.config.js, and a .prettierrc with a .prettierignore.
SSR and Nuxt are claimed, not demonstrated
The feature list says SSR Ready with support for Nuxt 3 and server-side rendering, and the repository topics include nuxt-demo. The monorepo has apps/docs, apps/playground and apps/backend, but the tree shown in the README does not include a Nuxt example application among them, and the topics entry suggests a nuxt-demo lives somewhere outside this tree.
That leaves an honest gap. None of the README examples show a Nuxt integration, and the README does not describe how the browser only Stripe components are handled during server rendering, whether they are wrapped in a client only boundary or lazily mounted. For an SSR application, that is the first question to ask, and the answer is in the guides at vuestripe.com/guide/introduction rather than on this page.
The other limitation worth naming is version coupling. Because the library requires @stripe/stripe-js ^10.0.0, you cannot adopt it while pinning an older Stripe.js, and the v5 to v6 migration is a breaking change with its own guide. There is also the practical point that the payment element components are inherently client side: they mount iframes and talk to Stripe over the network, so any server side rendering story has to keep them out of the server render pass.
The library's own comparison point is the raw Stripe.js API. Using vue-stripe means giving up direct control of the underlying Stripe.js calls in exchange for Vue shaped components, composables with typed returns, and a documented mapping of every Stripe.js method. A team that already has a thin hand written wrapper around Stripe.js, and prefers to keep that control, has little reason to switch.
Editorial conclusion
vue-stripe fits teams already on Vue who want Stripe payment forms without hand-rolling Stripe.js lifecycle code, and its MIT licence and full Stripe.js coverage make it a low friction choice. It is the wrong fit for a Nuxt or SSR project that cannot run the browser only components on the server, or for anyone who needs a v5 stable API, since v6 changed the surface and the migration guide is the first document to read. Verify first that your Vue version satisfies the required range, that the Stripe.js 10 requirement is acceptable in your tenant, and that you can work with a release the maintainer calls an early one maintained largely alone.
Frequently asked questions
Which Vue versions does vue-stripe support?
The requirements table lists vue at ^2.7.0 || ^3.0.0, and the README notes that Vue 2.6 is not supported. The feature list says one build serves both Vue 3 and Vue 2.7, tested on each in CI.
How do I install vue-stripe?
Run npm install @vue-stripe/vue-stripe@^6 @stripe/stripe-js@^10, then import the component styles once, for example with import '@vue-stripe/vue-stripe/style.css' in main.ts.
Why does usePaymentIntent return nothing outside VueStripeElements?
The composables read the Stripe context that the provider and the elements container set up, so the README says they must be called in a component rendered inside VueStripeElements. A component that sits outside that container has no context to read.
Is vue-stripe usable with Nuxt and SSR?
The README's feature list states SSR Ready with support for Nuxt 3 and server-side rendering. The README does not show a Nuxt example or describe how the client only Stripe components are kept out of the server render pass, so the guides at vuestripe.com are the place to check that.
What licence is vue-stripe under and who maintains it?
The licence is MIT, held in the LICENSE file. The README states the project is maintained largely by one person in limited spare time, with AI used as an assistant while the maintainer reviews and approves every change.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/vue-stripe-vue-stripe)Was this useful?