Integrating React Stripe Checkout With Next.js ECommerce

Imran Sayed
3 min readMay 25, 2021

--

npm i stripe @stripe/react-stripe-js @stripe/stripe-js axios

Create an account on stripe

Create an account on stripe and get the test publishable key and secret key. Add it to the .env file

NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_test_xxxx
STRIPE_SECRET_KEY=sk_test_xxxx

Create a stripe intent

Create a file called `stripe-payment-intent.js` under pages/api folder of your next.js app

import Stripe from "stripe";

const stripe = new Stripe(process.env.STRIPE_SECRET_KEY);

export default async (req, res) => {
if (req.method === "POST") {
try {
const { amount } = req.body;
const paymentIntent = await stripe.paymentIntents.create({
amount,
currency: "usd"
});

res.status(200).send(paymentIntent.client_secret);
} catch (err) {
res.status(500).json({ statusCode: 500, message: err.message });
}
} else {
res.setHeader("Allow", "POST");
res.status(405).end("Method Not Allowed");
}
};

Stripe Checkout Form

Now create a component called stripe checkout form.

import { useState } from "react";
import { CardElement, useStripe, useElements } from "@stripe/react-stripe-js";

import axios from "axios";
import Router from "next/router";
import {CARD_OPTIONS} from "../../constants/stripe";

const StripeCheckoutForm = () => {
const [isProcessing, setProcessingTo] = useState(false);
const [checkoutError, setCheckoutError] = useState();

const stripe = useStripe();
const elements = useElements();

/**
* The cardElements onChange prop can be used to
* add a handler for setting any errors.
*
@param event
*/
const handleCardDetailsChange = event => {
event.error ? setCheckoutError(event.error.message) : setCheckoutError();
};

const handleFormSubmit = async ev => {
ev.preventDefault();

/**
* We disable the form, until the stripe.js has finished
* loading.
*/
if (!stripe || !elements) {
return;
}

const billingDetails = {
name: 'Imran Sayed',
email: 'codeytek@gmail.com',
address: {
city: 'Pune',
line1: 'Address 1',
state: 'my state',
postal_code: '2200'
}
};

setProcessingTo(true);

const cardElement = elements.getElement("card");
const price = 10;

try {
const { data: clientSecret } = await axios.post("/api/stripe-payment-intent", {
amount: price * 100
});

const paymentMethodReq = await stripe.createPaymentMethod({
type: "card",
card: cardElement,
billing_details: billingDetails
});

if (paymentMethodReq.error) {
setCheckoutError(paymentMethodReq.error.message);
setProcessingTo(false);
return;
}

const { error } = await stripe.confirmCardPayment(clientSecret, {
payment_method: paymentMethodReq.paymentMethod.id
});

if (error) {
setCheckoutError(error.message);
setProcessingTo(false);
return;
}

// On successful payment, redirect to thank you page.
await Router.push("/thank-you")
} catch (err) {
setCheckoutError(err.message);
}
};

return (
<div className="stripe-form-container">
<form onSubmit={handleFormSubmit} className="stripe-form w-308px lg:w-600px border border px-4 lg:px-8 py-6 lg:py-10 m-auto">
<h2 className="text-white mb-6 uppercase font-600">Stripe Payment: Pay with card</h2>
<div className="mb-4">
<h6 className="text-sm mb-1 text-white">Card Information</h6>
<CardElement
options={CARD_OPTIONS}
onChange={handleCardDetailsChange}
/>
</div>
{checkoutError ? <div className="text-sm my-4 text-white">{checkoutError}</div> : null}
<button className="bg-pink-400 hover:bg-pink-300 text-white font-bold py-2 px-4" disabled={isProcessing || !stripe}>
{isProcessing ? "Processing..." : `Pay $100`}
</button>
</form>
</div>
);
};

export default StripeCheckoutForm;

Card options for styles can be placed in constants directory.

export const CARD_OPTIONS = {
iconStyle: "solid",
hidePostalCode: true,
style: {
base: {
iconColor: "#c4f0ff",
color: "#fff",
fontWeight: 500,
fontFamily: "Roboto, Open Sans, Segoe UI, sans-serif",
fontSize: "16px",
fontSmoothing: "antialiased",
":-webkit-autofill": {
color: "#fce883"
},
"::placeholder": {
color: "#87bbfd"
}
},
invalid: {
iconColor: "#ffc7ee",
color: "#ffc7ee"
}
}
};

Stripe Checkout Page

Create a page called `page/stripe-checkout.js`

import { Elements } from "@stripe/react-stripe-js";
import { loadStripe } from "@stripe/stripe-js";
import StripeCheckoutForm from "../src/components/stripe/stripe-checkout-form";

const StripeCheckout = () => {

const stripePromise = loadStripe(process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY);

return (
<Elements stripe={stripePromise}>
<StripeCheckoutForm/>
</Elements>
);
};

export default StripeCheckout;

Thank you Page
Create a page called `page/thankyou.js`

const ThankYou = () => {
return 'Thank you'
}

export default ThankYou;

Now go to localhost/3000/stripe-checkout

Once the payment is made it will be redirected to thank you page.

For more reference visit
https://stripe.com/docs/stripe-js/react

--

--

Imran Sayed
Imran Sayed

Written by Imran Sayed

👤 Full Stack Developer at rtCamp, Speaker, Blogger, YouTuber, Wordpress, React, Node, Laravel Developer http://youtube.com/ImranSayedDev