How to integrate Stripe in React
Integrating Stripe in React requires both a server-side component to create payment intents and a client-side component to collect card details securely using Stripe’s hosted fields.
As the creator of CoreUI with 25 years of web development experience, I’ve implemented Stripe payments in multiple production e-commerce applications and the most common mistake is trying to process payments from the frontend — always create payment intents on your server.
Stripe’s @stripe/react-stripe-js library provides pre-built, PCI-compliant form elements that never expose raw card data to your application.
This approach keeps you out of PCI scope and lets Stripe handle security compliance.
Install Stripe’s React and browser libraries.
npm install @stripe/stripe-js @stripe/react-stripe-js
Create a payment intent on your server (Node.js example):
// server: POST /api/create-payment-intent
import Stripe from 'stripe'
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY)
app.post('/api/create-payment-intent', async (req, res) => {
const { amount, currency = 'usd' } = req.body
const paymentIntent = await stripe.paymentIntents.create({
amount: Math.round(amount * 100), // cents
currency,
automatic_payment_methods: { enabled: true }
})
res.json({ clientSecret: paymentIntent.client_secret })
})
The server creates the payment intent and returns only the client_secret. Never expose your STRIPE_SECRET_KEY to the frontend. The client_secret is safe to send to the client — it can only confirm this specific payment, not create new ones.
Setting Up the Stripe Provider
Wrap your checkout in the Stripe Elements provider.
// App.jsx
import { loadStripe } from '@stripe/stripe-js'
import { Elements } from '@stripe/react-stripe-js'
import { CheckoutForm } from './CheckoutForm'
const stripePromise = loadStripe(import.meta.env.VITE_STRIPE_PUBLISHABLE_KEY)
export default function App() {
return (
<Elements stripe={stripePromise}>
<CheckoutForm amount={29.99} />
</Elements>
)
}
loadStripe is called outside the component to avoid reloading the Stripe.js script on every render. The Elements provider makes the Stripe context available to all child components.
The Checkout Form
Use PaymentElement and confirm the payment on submit.
// CheckoutForm.jsx
import { useState, useEffect } from 'react'
import { useStripe, useElements, PaymentElement } from '@stripe/react-stripe-js'
export function CheckoutForm({ amount }) {
const stripe = useStripe()
const elements = useElements()
const [clientSecret, setClientSecret] = useState('')
const [message, setMessage] = useState('')
const [processing, setProcessing] = useState(false)
useEffect(() => {
fetch('/api/create-payment-intent', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ amount })
})
.then(r => r.json())
.then(({ clientSecret }) => setClientSecret(clientSecret))
}, [amount])
async function handleSubmit(e) {
e.preventDefault()
if (!stripe || !elements || !clientSecret) return
setProcessing(true)
const { error } = await stripe.confirmPayment({
elements,
confirmParams: {
return_url: `${window.location.origin}/payment-success`
}
})
if (error) {
setMessage(error.message)
}
setProcessing(false)
}
if (!clientSecret) return <p>Loading payment form...</p>
return (
<form onSubmit={handleSubmit}>
<PaymentElement />
<button type="submit" disabled={!stripe || processing}>
{processing ? 'Processing...' : `Pay $${amount}`}
</button>
{message && <p className="error">{message}</p>}
</form>
)
}
PaymentElement renders Stripe’s hosted UI for card, Apple Pay, Google Pay, and other payment methods. stripe.confirmPayment submits the form data directly to Stripe — your server never sees raw card numbers. After successful payment, Stripe redirects to return_url.
Best Practice Note
This is the recommended Stripe integration pattern for CoreUI React e-commerce templates. Always pass the Elements component a clientSecret using the options prop when you have it in advance — this enables Stripe to begin loading payment method UI immediately. For the full checkout flow including order summary and shipping, see how to build a checkout page in React.



