VueStripeCheckoutFormProvider
Initializes the Checkout Form via stripe.initCheckoutFormSdk() and provides the Checkout Form SDK to descendants. Place VueStripeCheckoutForm inside it to render Stripe's complete checkout form on your page, and confirm with the useCheckoutForm composable. Choosing an integration compares it with the other Checkout options.
- Use it inside
VueStripeProvider, or in an app that installs thecreateVueStripe()plugin. - Pass the
client_secretof a Checkout Session created on your server withui_mode: 'form'(Stripe API version2026-03-25.dahliaor later). Add the Checkout Form shows the server code. - The provider shows its
#loadingslot until the Stripe instance exists, then callsstripe.initCheckoutFormSdk(), which returns the SDK synchronously, and renders its children at once.@readyfires when the session actions have loaded (loadActions()), and@changeon every session change.
Beta: requires Stripe access
The Checkout Form SDK is a Stripe beta (ui_mode: 'form'). Your Stripe account needs access; contact Stripe support to join. Some form options have their own gate: the compact layout is a separate private preview, and without it the form reports "The compact layout is not available for your account" through its #error slot and @loaderror.
Live demo
The Checkout Form demo pays a Checkout Session with this provider, VueStripeCheckoutForm and useCheckoutForm().
Usage
<template>
<VueStripeProvider :publishable-key="publishableKey">
<VueStripeCheckoutFormProvider :fetch-client-secret="fetchClientSecret">
<PayForm />
</VueStripeCheckoutFormProvider>
</VueStripeProvider>
</template>
<script setup lang="ts">
import { VueStripeProvider, VueStripeCheckoutFormProvider } from '@vue-stripe/vue-stripe'
import '@vue-stripe/vue-stripe/style.css' // once, e.g. in main.ts
import PayForm from './PayForm.vue'
const publishableKey = import.meta.env.VITE_STRIPE_PUBLISHABLE_KEY
// From your backend: stripe.checkout.sessions.create({ ui_mode: 'form', ... })
// Called by the provider in the browser only, once Stripe.js has loaded
const fetchClientSecret = () =>
fetch('/api/checkout-form-session', { method: 'POST' })
.then((res) => res.json())
.then((data) => data.clientSecret)
</script>A Promise in client-secret works too, with two limits: a request that fails before the provider mounts is reported as an uncaught rejection (see Errors), and on a server-rendered page the request would start on the server (see Fetch client secrets in the browser).
<!-- PayForm.vue -->
<template>
<VueStripeCheckoutForm @confirm="onConfirm" />
<p v-if="message">{{ message }}</p>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { VueStripeCheckoutForm, useCheckoutForm } from '@vue-stripe/vue-stripe'
import type { StripeCheckoutFormConfirmEvent } from '@vue-stripe/vue-stripe'
const { confirm } = useCheckoutForm()
const message = ref('')
// The form's Pay button (or a wallet) fires @confirm; hand the event to Stripe.
const onConfirm = async (event: StripeCheckoutFormConfirmEvent) => {
const result = await confirm({ formConfirmEvent: event })
if (result.type === 'error') message.value = result.error.message
}
</script>Props
| Prop | Type | Required | Description |
|---|---|---|---|
clientSecret | string | Promise<string> | No* | Client secret of a ui_mode: 'form' Checkout Session, or a Promise resolving to it. A Promise is checked before Stripe gets its value, see Errors |
fetchClientSecret | () => Promise<string> | No* | Function returning the client secret. The provider calls it once Stripe.js has loaded and checks the result before Stripe gets it. Takes precedence over clientSecret |
appearance | Omit<Appearance, 'rules'> | No | Appearance of the form; the Form SDK does not accept rules |
loader | 'auto' | 'always' | 'never' | No | Whether Stripe shows a loader while the form loads |
fonts | Array<CssFontSource | CustomFontSource> | No | Custom fonts for the form |
savedPaymentMethod | SavedPaymentMethodOption | No | Saved payment methods: enableSave, enableRedisplay ('auto' or 'never') |
defaultValues | object | No | Prefill email, phoneNumber, billingAddress, shippingAddress |
* Provide either clientSecret or fetchClientSecret. If neither is set, the error slot renders and @error fires.
The props are read once, when the SDK is initialized. To use another session, re-mount the provider (for example with a :key). To restyle the form later, call useCheckoutForm().changeAppearance().
defaultValues
interface DefaultValues {
email?: string
phoneNumber?: string
billingAddress?: StripeCheckoutContact
shippingAddress?: StripeCheckoutContact
}The defaults go to the session as on VueStripeCheckoutElementsProvider, so Stripe refuses the same ones: email on a session that already has the customer's email, and phoneNumber unless the session was created with phone_number_collection: { enabled: true }.
Events
| Event | Payload | Description |
|---|---|---|
@ready | StripeCheckoutFormLoadActionsSuccess | Emitted once loadActions() resolves. Payload is the Form SDK actions object |
@change | StripeCheckoutSession | Emitted on every Stripe change event with the new session snapshot |
@error | string | Emitted if fetchClientSecret or a clientSecret Promise rejects or resolves no client secret, initCheckoutFormSdk() throws, loadActions() returns an error or rejects, or no client secret is given; also when Stripe.js fails to load under the plugin without a VueStripeProvider (the plugin logs that failure itself). loading turns false. See Errors |
Errors
| Error | Cause | Fix |
|---|---|---|
VueStripeProviderError (thrown) | Not inside VueStripeProvider, in an app without createVueStripe() | Wrap the provider in VueStripeProvider |
requires a clientSecret (string or Promise) or fetchClientSecret prop | Neither prop given | Pass one of them |
| The rejection's message | fetchClientSecret or the clientSecret Promise rejected, for example Failed to fetch (connection refused) or a JSON SyntaxError (the route answered an HTML error page) | Fix the route, then re-mount the provider |
fetchClientSecret did not resolve to a client secret, clientSecret did not resolve to a client secret | The function or the Promise resolved an empty or non-string value, for example undefined when the route answered 500 with a JSON error body | Resolve the session's client_secret |
| Stripe error message | initCheckoutFormSdk() threw or loadActions() failed: invalid or expired client secret, a session that is not ui_mode: 'form', or a default the session refuses | Create a new session on your server, or drop the default |
The provider checks the secret before Stripe.js gets it, so these failures reach only @error and #error. Two cases still log an uncaught error in the browser console:
- A client secret string Stripe.js cannot parse (not of the form
{cs_id}_secret_{secret}): Stripe.js reports it throughloadActions()and also as its ownUncaught (in promise) IntegrationError. - A
clientSecretPromise that rejects before the provider exists. UnderVueStripeProvider, the provider mounts only once Stripe.js has loaded, so a request that fails fast rejects while nothing handles it. Passfetch-client-secretinstead: the provider calls it once Stripe.js has loaded.
Slots
| Slot | Props | Rendered when |
|---|---|---|
default | { checkout, actions, session, loading } | As soon as the Checkout Form SDK exists (before the actions load) |
loading | - | Until the Checkout Form SDK exists (Stripe.js still loading) |
error | { error } | Initialization failed |
The default slot renders early so VueStripeCheckoutForm can mount while the actions are still loading. Its loading prop (and useCheckoutForm().loading) stays true until loadActions() resolves; actions and session are null until then.
| Slot Prop | Type | Description |
|---|---|---|
checkout | StripeCheckoutFormSdk | The Checkout Form SDK instance |
actions | StripeCheckoutFormLoadActionsSuccess | null | Form SDK actions (null until loaded) |
session | StripeCheckoutSession | null | Current session snapshot (null until loaded) |
loading | boolean | true until the actions have loaded |
Components inside the provider
| Component | Created with | Accepted options |
|---|---|---|
| VueStripeCheckoutForm | createForm() | layout, contacts, expressCheckout, features |
| VueStripeCurrencySelectorElement | createCurrencySelectorElement() | None |
The Form SDK creates nothing else: any other element component placed inside this provider sets its error state ("... is not available inside VueStripeCheckoutFormProvider") and logs an error. When you render a VueStripeCurrencySelectorElement yourself, the form leaves out its built-in currency picker.
Provides
| Key | Type | Description |
|---|---|---|
checkout | Ref<StripeCheckoutFormSdk | null> | The Checkout Form SDK instance |
actions | Ref<StripeCheckoutFormLoadActionsSuccess | null> | Form SDK actions, once loadActions() resolves |
session | Ref<StripeCheckoutSession | null> | Reactive session snapshot (updates on every Stripe change) |
loading | Ref<boolean> | true until the actions have loaded |
error | Ref<string | null> | Initialization error, if any |
The provider uses its own injection key, so useCheckoutSession() does not work inside it. Access these via useCheckoutForm().
TypeScript
The component's props, event payloads and slot props are typed on Vue 2.7 and Vue 3: vue-tsc checks a handler's parameter against the payload in Events, and a slot prop against Slots.
<script setup lang="ts">
import { VueStripeCheckoutFormProvider, VueStripeCheckoutForm } from '@vue-stripe/vue-stripe'
import type {
StripeCheckoutFormLoadActionsSuccess,
StripeCheckoutSession,
VueStripeCheckoutFormProviderProps
} from '@vue-stripe/vue-stripe'
const config: VueStripeCheckoutFormProviderProps = {
clientSecret: 'cs_test_..._secret_...',
appearance: { theme: 'stripe' },
savedPaymentMethod: { enableSave: 'never' }
}
const onReady = (actions: StripeCheckoutFormLoadActionsSuccess) => {
console.log(actions.getSession().total.total.amount)
}
const onChange = (session: StripeCheckoutSession) => {
console.log('Status:', session.status.type)
}
</script>
<template>
<VueStripeCheckoutFormProvider v-bind="config" @ready="onReady" @change="onChange">
<VueStripeCheckoutForm />
</VueStripeCheckoutFormProvider>
</template>See Also
- VueStripeCheckoutForm - the form itself
- useCheckoutForm - confirm and drive the session from descendants
- Checkout Form guide - end-to-end walkthrough
- VueStripeCheckoutElementsProvider - compose your own form from elements instead
