usePaymentElement()
The usePaymentElement()
hook is used to control the payment form rendered by the <PaymentElement /> component. It provides the necessary state and methods to submit payment details to a payment provider like Stripe.
This hook must be used within a component that is a descendant of the <PaymentElementProvider />
component. It is typically used in a checkout flow that prompts a user to add a new payment method, or for adding a new payment method outside of a checkout.
Parameters
usePaymentElement()
doesn't accept any parameters. It derives its state and configuration from the nearest <PaymentElementProvider />.
Returns
usePaymentElement()
returns an object with the following properties:
- Name
submit()
- Type
() => Promise<{ data: { gateway: 'stripe'; paymentToken: string } | null; error: PaymentElementError | null}>
- Description
A function that submits the payment form data to the payment provider. It returns a promise that resolves with either a
data
object containing a payment token on success, or anerror
object on failure.
- Name
reset()
- Type
() => Promise<void>
- Description
A function that resets the payment form to its initial, empty state.
- Name
isFormReady
- Type
boolean
- Description
A boolean that indicates if the payment form UI has been rendered and is ready for user input. This is useful for disabling a submit button until the form is interactive.
- Name
isProviderReady
- Type
boolean
- Description
A boolean that indicates if the underlying payment provider (e.g. Stripe) has been fully initialized.
- Name
provider
- Type
{ name: 'stripe' } | undefined
- Description
An object containing information about the initialized payment provider. It is
undefined
untilisProviderReady
istrue
.
Payment element components
The usePaymentElement()
hook works in conjunction with the <PaymentElementProvider />
and <PaymentElement />
components.
<PaymentElementProvider />
The <PaymentElementProvider />
component sets up the context for the payment element. It fetches all the necessary data from the payment provider (e.g., Stripe) and makes it available to its children.
Properties
- Name
checkout?
- Type
- Description
An optional checkout resource object. When provided, the payment element is scoped to the specific checkout session.
- Name
for?
- Type
'user' | 'organization'
- Description
Specifies whether the payment method is being added for a user or an organization. Defaults to
'user'
.
- Name
stripeAppearance?
- Type
object
- Description
An optional object to customize the appearance of the Stripe Payment Element. This allows you to match the form's styling to your application's theme.
- Name
paymentDescription?
- Type
string
- Description
An optional description to display to the user within the payment element UI.
<PaymentElement />
This component renders the actual payment form from the provider (e.g., the Stripe Payment Element). It should be rendered as a child of <PaymentElementProvider />
.
Properties
- Name
fallback?
- Type
ReactNode
- Description
Optional fallback content, such as a loading skeleton, to display while the payment form is being initialized.
Examples
The following example demonstrates how to create a billing page where a user can add a new payment method. It is split into two components:
<UserBillingPage />
: Sets up the<PaymentElementProvider />
, which specifies that the payment actions within its children arefor
theuser
.<AddPaymentMethodForm />
: Renders the payment form and handles the submission logic. It usesusePaymentElement()
to get thesubmit
function anduseUser()
to get theuser
object. When the form is submitted, it first creates a payment token and then attaches it to the user.
import { ClerkLoaded } from '@clerk/nextjs'
import { PaymentElementProvider } from '@clerk/nextjs/experimental'
import { AddPaymentMethodForm } from './AddPaymentMethodForm'
export default function Page() {
return (
<div>
<h1>Billing Settings</h1>
<ClerkLoaded>
<PaymentElementProvider for="user">
<AddPaymentMethodForm />
</PaymentElementProvider>
</ClerkLoaded>
</div>
)
}
'use client'
import { useUser } from '@clerk/nextjs'
import { usePaymentElement, PaymentElement } from '@clerk/nextjs/experimental'
import { useState } from 'react'
export function AddPaymentMethodForm() {
const { user } = useUser()
const { submit, isFormReady } = usePaymentElement()
const [isSubmitting, setIsSubmitting] = useState(false)
const [error, setError] = useState<string | null>(null)
const handleAddPaymentMethod = async (e: React.FormEvent) => {
e.preventDefault()
if (!isFormReady || !user) {
return
}
setError(null)
setIsSubmitting(true)
try {
// 1. Submit the form to the payment provider to get a payment token
const { data, error } = await submit()
// Usually a validation error from stripe that you can ignore.
if (error) {
setIsSubmitting(false)
return
}
// 2. Use the token to add the payment source to the user
await user.addPaymentSource(data)
// 3. Handle success (e.g., show a confirmation, clear the form)
alert('Payment method added successfully!')
} catch (err: any) {
setError(err.message || 'An unexpected error occurred.')
} finally {
setIsSubmitting(false)
}
}
return (
<form onSubmit={handleAddPaymentMethod}>
<h3>Add a new payment method</h3>
<PaymentElement />
<button type="submit" disabled={!isFormReady || isSubmitting}>
{isSubmitting ? 'Saving...' : 'Save Card'}
</button>
{error && <p style={{ color: 'red' }}>{error}</p>}
</form>
)
}
Use PaymentElement in a checkout flow
Add a new payment method during checkout
Use PaymentElement outside of a checkout flow
Add a new payment method outside of a checkout flow
Feedback
Last updated on