Payment with Stripe in React Storefront
In this guide, you'll learn how to use Stripe for payment during checkout in a React-based storefront.
1. Install Stripe SDK#
In your storefront, use the following command to install Stripe's JS and React SDKs:
2. Add Stripe Environment Variables#
Next, add an environment variable holding your Stripe publishable API key.
For example:
NEXT_PUBLIC
. If your storefront's framework requires a different prefix, make sure to change it.3. Create Stripe Component#
You can now create a Stripe component that renders the Stripe UI to accept payment.
For example, you can create a file holding the following Stripe component:
- This example uses the
useCart
hook defined in the Cart React Context guide. - Learn how to install and configure the JS SDK in the JS SDK documentation.
1"use client"2 3import { 4 CardElement, 5 Elements, 6 useElements, 7 useStripe,8} from "@stripe/react-stripe-js"9import { loadStripe } from "@stripe/stripe-js"10import { useCart } from "@/providers/cart"11import { useState } from "react"12import { sdk } from "@/lib/sdk"13 14const stripe = loadStripe(15 process.env.NEXT_PUBLIC_STRIPE_PK || "temp"16)17 18export default function StripePayment() {19 const { cart } = useCart()20 const clientSecret = cart?.payment_collection?.21 payment_sessions?.[0].data.client_secret as string22 23 return (24 <div>25 <Elements stripe={stripe} options={{26 clientSecret,27 }}>28 <StripeForm clientSecret={clientSecret} />29 </Elements>30 </div>31 )32}33 34const StripeForm = ({ 35 clientSecret,36}: {37 clientSecret: string | undefined38}) => {39 const { cart, refreshCart } = useCart()40 const [loading, setLoading] = useState(false)41 42 const stripe = useStripe()43 const elements = useElements()44 45 async function handlePayment(46 e: React.MouseEvent<HTMLButtonElement, MouseEvent>47 ) {48 e.preventDefault()49 const card = elements?.getElement(CardElement)50 51 if (52 !stripe || 53 !elements ||54 !card ||55 !cart ||56 !clientSecret57 ) {58 return59 }60 61 setLoading(true)62 stripe?.confirmCardPayment(clientSecret, {63 payment_method: {64 card,65 billing_details: {66 name: cart.billing_address?.first_name,67 email: cart.email,68 phone: cart.billing_address?.phone,69 address: {70 city: cart.billing_address?.city,71 country: cart.billing_address?.country_code,72 line1: cart.billing_address?.address_1,73 line2: cart.billing_address?.address_2,74 postal_code: cart.billing_address?.postal_code,75 },76 },77 },78 })79 .then(({ error }) => {80 if (error) {81 // TODO handle errors82 console.error(error)83 return84 }85 86 sdk.store.cart.complete(cart.id)87 .then((data) => {88 if (data.type === "cart" && data.cart) {89 // an error occured90 console.error(data.error)91 } else if (data.type === "order" && data.order) {92 // TODO redirect to order success page93 alert("Order placed.")94 console.log(data.order)95 refreshCart()96 }97 })98 })99 .finally(() => setLoading(false))100 }101 102 return (103 <form>104 <CardElement />105 <button106 onClick={handlePayment}107 disabled={loading}108 >109 Place Order110 </button>111 </form>112 )113}
In the code snippet above, you:
- Create a
StripePayment
component that wraps the actual form with Stripe'sElements
component.- In the
StripePayment
component, you obtain the client secret from the payment session'sdata
field. This is set in the Medusa application after you initialize the payment session using the Initialize Payment Sessions API route.
- In the
- Create a
StripeForm
component that holds the actual form. In this component, you implement ahandlePayment
function that does the following:- Use Stripe's
confirmCardPayment
method to accept the card details from the customer. - Once the customer enters their card details and submit their order, the resolution function of the
confirmCardPayment
method is executed. - In the resolution function, you send a request to the Complete Cart API route to complete the cart and place the order.
- In the received response of the request, if the
type
iscart
, it means that the cart completion failed. The error is set in theerror
response field. - If the
type
isorder
, it means the card was completed and the order was placed successfully. You can access the order in theorder
response field. - When the order is placed, you refresh the cart. You can redirect the customer to an order success page at this point. The redirection logic depends on the framework you're using.
- Use Stripe's
4. Use the Stripe Component#
Finally, use the Stripe component in the checkout flow. You should render it after the customer chooses Stripe as a payment provider.
For example, you can use it in the getPaymentUi
function defined in the Payment Checkout Step guide:
1const getPaymentUi = useCallback(() => {2 const activePaymentSession = cart?.payment_collection?.3 payment_sessions?.[0]4 if (!activePaymentSession) {5 return6 }7 8 switch(true) {9 case activePaymentSession.provider_id.startsWith("pp_stripe_"):10 return <StripePayment />11 // ...12 }13} , [cart])
More Resources#
Refer to Stripe's documentation for more details on integrating it in your storefront.