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 - dataobject containing a payment token on success, or an- errorobject 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 - undefineduntil- isProviderReadyis- true.
 
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 are- forthe- user.
- <AddPaymentMethodForm />: Renders the payment form and handles the submission logic. It uses- usePaymentElement()to get the- submitfunction and- useUser()to get the- userobject. 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