Integrate stripe payment gateway in React
Today weāll explain to you how to integrate stripe payment gateway in React. We will split this integration in the two parts such as React (Frontend) and Node.js (Backend).
In this article, will create a react application that contains the product cart and checkout form as shown below.
Demo Application
Output - Integrate stripe payment gateway in React - Clue Mediator
Stripe payment gateway integration.
- Part 1 - Integrate stripe payment gateway in React (You are hereā¦)
- Part 2 - Confirm a stripe paymentIntent using Node.js
Steps to integrate stripe payment gateway in React
- Create a stripe account
- Collect the API keys
- Create a react application
- Install npm dependency
- Design a checkout page
- Create a checkout form using stripe package
- Submit payment method to server
- Output
1. Create a stripe account
First of all, we have to create a stripe account using the Register Now link. It's a very straightforward process using the email address.
2. Collect the API keys
After successful login, you will be redirected on the Dashboard page and the API keys are always available on the dashboard. For the testing purpose, weāll use the test API keys. Check the following links for more information about the API keys.
Manage your API keys to authenticate requests with Stripe
There are two types of API keys.
- Publishable API key: Itās used in places like your Stripe.js, JavaScript code, or in an Android or iPhone app. Weāll use it in the React application.
- Secret API key: It should be kept confidential and only stored on your own servers. Weāll use it in the Node.js application.
3. Create a react application
Letās create a react application using the `create-react-app` package. For that simply run the following command to Create a React App.
npx create-react-app stripe-payment-gateway-react
4. Install npm dependency
We will use the @stripe/react-stripe-js and @stripe/stripe-js npm packages to integrate the stripe payment gateway in the react app. Run the following single command to install both packages simultaneously.
npm install --save @stripe/react-stripe-js @stripe/stripe-js
5. Design a checkout page
Now, we will design a checkout page using bootstrap with some sample records. Add the following bootstrap stylesheet to the `public.html` page.
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous">
You can also check How to add Bootstrap in React.
Letās add the following HTML and CSS of the checkout page to the react component.
App.js
import React, { useState } from 'react';
const successMessage = () => {
return (
<div class="success-msg">
<svg width="1em" height="1em" viewBox="0 0 16 16" class="bi bi-check2" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" d="M13.854 3.646a.5.5 0 0 1 0 .708l-7 7a.5.5 0 0 1-.708 0l-3.5-3.5a.5.5 0 1 1 .708-.708L6.5 10.293l6.646-6.647a.5.5 0 0 1 .708 0z"></path>
</svg>
<div class="title">Payment Successful</div>
</div>
)
}
const cart = () => {
return (<react class="fragment">
<h4 class="d-flex justify-content-between align-items-center mb-3">
<span class="text-muted">Your cart</span>
<span class="badge bg-secondary badge-pill">3</span>
</h4>
<ul class="list-group mb-3">
<li class="list-group-item d-flex justify-content-between lh-condensed">
<div>
<h6 class="my-0">Product name</h6>
<small class="text-muted">Brief description</small>
</div>
<span class="text-muted">ā¹1200</span>
</li>
<li class="list-group-item d-flex justify-content-between lh-condensed">
<div>
<h6 class="my-0">Second product</h6>
<small class="text-muted">Brief description</small>
</div>
<span class="text-muted">ā¹800</span>
</li>
<li class="list-group-item d-flex justify-content-between lh-condensed">
<div>
<h6 class="my-0">Third item</h6>
<small class="text-muted">Brief description</small>
</div>
<span class="text-muted">ā¹500</span>
</li>
<li class="list-group-item d-flex justify-content-between bg-light">
<div class="text-success">
<h6 class="my-0">Promo code</h6>
<small>EXAMPLECODE</small>
</div>
<span class="text-success">-ā¹500</span>
</li>
<li class="list-group-item d-flex justify-content-between">
<span>Total (INR)</span>
<strong>ā¹2000</strong>
</li>
</ul>
</react>)
}
function App() {
const [paymentCompleted, setPaymentCompleted] = useState(false);
return (
<div class="container">
<div class="py-5 text-center">
<h4>Stripe Integration - <a href="https://www.cluemediator.com/" target="_blank" rel="noopener noreferrer">Clue Mediator</a></h4>
</div>
<div class="row s-box">
{paymentCompleted ? successMessage() : <react class="fragment">
<div class="col-md-5 order-md-2 mb-4">
{cart()}
</div>
<div class="col-md-7 order-md-1">
{/* Checkout form */}
</div>
</react>}
</div>
</div>
);
}
export default App;
index.css
body {
margin: 20px;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
monospace;
}
.container {
width: 900px;
}
.s-box {
min-height: 433px;
border: 1px solid #ddd;
border-radius: 10px;
padding: 30px;
background-color: #f7f7f9;
box-shadow: 0 1px 1px rgba(0,0,0,0.15),
0 2px 2px rgba(0,0,0,0.15),
0 4px 4px rgba(0,0,0,0.15),
0 8px 8px rgba(0,0,0,0.15);
}
label {
margin-bottom: 3px;
}
.spinner-border {
width: 1.3rem;
height: 1.3rem;
border-width: .1em;
}
.success-msg {
color: #0f5132;
text-align: center;
margin-top: 120px;
}
.success-msg svg {
font-size: 60px;
border: 1px solid #0f5132;
border-radius: 30px;
padding: 10px;
}
.success-msg .title {
font-size: 25px;
margin-top: 10px;
}
6. Create a checkout form using stripe package
Itās time to create a checkout form using the stripe package. Here we will use the individual `Element` component to create a form. You can also use the `CardElement` to create a ready form.
CheckoutForm.js
import React, { useState } from 'react';
import {
useStripe, useElements,
CardNumberElement, CardExpiryElement, CardCvcElement
} from '@stripe/react-stripe-js';
const CARD_ELEMENT_OPTIONS = {
style: {
base: {
lineHeight: "27px",
color: "#212529",
fontSize: "1.1rem",
"::placeholder": {
color: "#aab7c4",
},
},
invalid: {
color: "#fa755a",
iconColor: "#fa755a",
},
},
};
export default function CheckoutForm(props) {
const [loading, setLoading] = useState(false);
const [errorMsg, setErrorMsg] = useState('');
const [name, setName] = useState('');
const [email, setEmail] = useState('');
const stripe = useStripe();
const elements = useElements();
const handleSubmit = async (event) => {
// We don't want to let default form submission happen here,
// which would refresh the page.
event.preventDefault();
if (!stripe || !elements) {
// Stripe.js has not yet loaded.
// Make sure to disable form submission until Stripe.js has loaded.
return;
}
};
return (
<react class="fragment">
<h4 class="d-flex justify-content-between align-items-center mb-3">
<span class="text-muted">Pay with card</span>
</h4>
<form onsubmit={handleSubmit}>
<div class="row">
<div class="col-md-6 mb-3">
<label for="cc-name">Name on card</label>
<input id="cc-name" type="text" class="form-control" value={name} onchange="{e" ==""> setName(e.target.value)}
/>
</div>
<div class="col-md-6 mb-3">
<label for="cc-email">Email</label>
<input id="cc-email" type="text" class="form-control" value={email} onchange="{e" ==""> setEmail(e.target.value)}
/>
</div>
</div>
<div class="row">
<div class="col-md-12 mb-3">
<label for="cc-number">Card Number</label>
<cardnumberelement id="cc-number" class="form-control" options={CARD_ELEMENT_OPTIONS}>
</cardnumberelement></div>
</div>
<div class="row">
<div class="col-md-6 mb-3">
<label for="expiry">Expiration Date</label>
<cardexpiryelement id="expiry" class="form-control" options={CARD_ELEMENT_OPTIONS}>
</cardexpiryelement></div>
<div class="col-md-6 mb-3">
<label for="cvc">CVC</label>
<cardcvcelement id="cvc" class="form-control" options={CARD_ELEMENT_OPTIONS}>
</cardcvcelement></div>
</div>
<hr class="mb-4">
<button class="btn btn-dark w-100" type="submit" disabled>
{loading ? <div class="spinner-border spinner-border-sm text-light" role="status"></div> : `PAY ā¹${props.amount}`}
</button>
{errorMsg && <div class="text-danger mt-2">{errorMsg}</div>}
</form>
</react>
);
}
To load the `CheckoutForm` component, we need to generate the `Stripe` object using the publishable API key. Check the following code.
App.js
import React, { useState } from 'react';
import { Elements } from '@stripe/react-stripe-js';
import { loadStripe } from '@stripe/stripe-js';
import CheckoutForm from './CheckoutForm';
// Make sure to call `loadStripe` outside of a componentās render to avoid
// recreating the `Stripe` object on every render.
const stripePromise = loadStripe("<your_publishable_key>");
const successMessage = () => {
return (
<div class="success-msg">
...
...
</div>
)
}
const cart = () => {
return (
<react class="fragment">
...
...
</react>
)
}
function App() {
const [paymentCompleted, setPaymentCompleted] = useState(false);
return (
<div class="container">
<div class="py-5 text-center">
<h4>Stripe Integration - <a href="https://www.cluemediator.com/" target="_blank" rel="noopener noreferrer">Clue Mediator</a></h4>
</div>
<div class="row s-box">
{paymentCompleted ? successMessage() : <react class="fragment">
<div class="col-md-5 order-md-2 mb-4">
{cart()}
</div>
<div class="col-md-7 order-md-1">
<elements stripe={stripePromise}>
<checkoutform amount={2000} setpaymentcompleted={setPaymentCompleted}>
</checkoutform></elements>
</div>
</react>}
</div>
</div>
);
}
export default App;
</your_publishable_key>
7. Submit payment method to server
In the last step, we need to create a payment method on button click of the `Pay`. After creating the payment method, we have to send that data to the backend like payment method id, name, email, amount, etc.
So letās create a `stripePaymentMethodHandler` method to submit that data to the backend.
script.js
const API_ENDPOINT = 'http://localhost:4000';
export const stripePaymentMethodHandler = async (data, cb) => {
const { amount, result } = data;
if (result.error) {
// show error in payment form
cb(result);
} else {
const paymentResponse = await stripePayment({
payment_method_id: result.paymentMethod.id,
name: result.paymentMethod.billing_details.name,
email: result.paymentMethod.billing_details.email,
amount: amount
});
console.log(paymentResponse);
cb(paymentResponse);
}
}
// place backend API call for payment
const stripePayment = async data => {
const res = await fetch(`${API_ENDPOINT}/pay`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data),
})
return await res.json();
}
Here, we have used the `API_ENDPOINT` as a backend server API endpoint where we will confirm the payment. Weāll see this step in the next article (Confirm a stripe paymentIntent using Node.js).
Letās call the above method from the `CheckoutForm` component.
CheckoutForm.js
import { stripePaymentMethodHandler } from './script';
...
...
export default function CheckoutForm(props) {
...
...
const handleSubmit = async (event) => {
// We don't want to let default form submission happen here,
// which would refresh the page.
event.preventDefault();
if (!stripe || !elements) {
// Stripe.js has not yet loaded.
// Make sure to disable form submission until Stripe.js has loaded.
return;
}
setLoading(true);
setErrorMsg('');
const paymentMethodObj = {
type: 'card',
card: elements.getElement(CardNumberElement),
billing_details: {
name,
email
},
};
const paymentMethodResult = await stripe.createPaymentMethod(paymentMethodObj);
stripePaymentMethodHandler({
result: paymentMethodResult,
amount: props.amount
}, handleResponse);
};
// callback method to handle the response
const handleResponse = response => {
setLoading(false);
if (response.error) {
setErrorMsg(typeof response.error === 'string' ? response.error : response.error.message);
return;
}
props.setPaymentCompleted(response.success ? true : false);
};
return (
<react class="fragment">
...
...
</react>
);
}
Check this link for the more information of the stripe integration.
8. Output
Run the react application and check the output in the browser.
Note: Here, we have used the backend server API to confirm the payment, which we explained in the next article.
Thatās it for today.
Thank you for reading. Happy Coding..!!