Skip to content

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 the createVueStripe() plugin.
  • Pass the client_secret of a Checkout Session created on your server with ui_mode: 'form' (Stripe API version 2026-03-25.dahlia or later). Add the Checkout Form shows the server code.
  • The provider shows its #loading slot until the Stripe instance exists, then calls stripe.initCheckoutFormSdk(), which returns the SDK synchronously, and renders its children at once. @ready fires when the session actions have loaded (loadActions()), and @change on 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 ​

vue
<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).

vue
<!-- 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 ​

PropTypeRequiredDescription
clientSecretstring | 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
appearanceOmit<Appearance, 'rules'>NoAppearance of the form; the Form SDK does not accept rules
loader'auto' | 'always' | 'never'NoWhether Stripe shows a loader while the form loads
fontsArray<CssFontSource | CustomFontSource>NoCustom fonts for the form
savedPaymentMethodSavedPaymentMethodOptionNoSaved payment methods: enableSave, enableRedisplay ('auto' or 'never')
defaultValuesobjectNoPrefill 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 ​

ts
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 ​

EventPayloadDescription
@readyStripeCheckoutFormLoadActionsSuccessEmitted once loadActions() resolves. Payload is the Form SDK actions object
@changeStripeCheckoutSessionEmitted on every Stripe change event with the new session snapshot
@errorstringEmitted 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 ​

ErrorCauseFix
VueStripeProviderError (thrown)Not inside VueStripeProvider, in an app without createVueStripe()Wrap the provider in VueStripeProvider
requires a clientSecret (string or Promise) or fetchClientSecret propNeither prop givenPass one of them
The rejection's messagefetchClientSecret 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 secretThe function or the Promise resolved an empty or non-string value, for example undefined when the route answered 500 with a JSON error bodyResolve the session's client_secret
Stripe error messageinitCheckoutFormSdk() threw or loadActions() failed: invalid or expired client secret, a session that is not ui_mode: 'form', or a default the session refusesCreate 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 through loadActions() and also as its own Uncaught (in promise) IntegrationError.
  • A clientSecret Promise that rejects before the provider exists. Under VueStripeProvider, the provider mounts only once Stripe.js has loaded, so a request that fails fast rejects while nothing handles it. Pass fetch-client-secret instead: the provider calls it once Stripe.js has loaded.

Slots ​

SlotPropsRendered 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 PropTypeDescription
checkoutStripeCheckoutFormSdkThe Checkout Form SDK instance
actionsStripeCheckoutFormLoadActionsSuccess | nullForm SDK actions (null until loaded)
sessionStripeCheckoutSession | nullCurrent session snapshot (null until loaded)
loadingbooleantrue until the actions have loaded

Components inside the provider ​

ComponentCreated withAccepted options
VueStripeCheckoutFormcreateForm()layout, contacts, expressCheckout, features
VueStripeCurrencySelectorElementcreateCurrencySelectorElement()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 ​

KeyTypeDescription
checkoutRef<StripeCheckoutFormSdk | null>The Checkout Form SDK instance
actionsRef<StripeCheckoutFormLoadActionsSuccess | null>Form SDK actions, once loadActions() resolves
sessionRef<StripeCheckoutSession | null>Reactive session snapshot (updates on every Stripe change)
loadingRef<boolean>true until the actions have loaded
errorRef<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.

vue
<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 ​