Stripe is a leading online payment processor that can be easily integrated into any type of application. Many businesses across the globe use Stripe to accept money for their products and services.
This guide will be a perfect start for you to understand how payment gateways work and how you can integrate Stripe into an existing React application.
In this guide, you will be creating a product card, as shown below, and integrating it with Stripe.
The complete payment processing flow is described below:
The user enters details into the card form.
The client application sends the card details to the Stripe API.
The Stripe API performs tokenization and returns a token object for the card.
The client application sends the card token to the backend application with other data related to the purchase.
Get started with setting up the product card in the App.js
file by adding the product image.
1const App = () => {
2 return (
3 <div className="App">
4 <div className="product">
5 <img
6 src="https://images.pexels.com/photos/18105/pexels-photo.jpg?auto=compress"
7 alt="laptop"
8 style={{ width: "100%", height: "auto" }}
9 />
10 <div>
11 {
12 // Checkout component
13 }
14 </div>
15 </div>
16 </div>
17 );
18};
You need to install two Stripe libraries to get started with the integration.
1npm i @stripe/stripe-js @stripe/react-stripe-js
The stripe-js
library includes the main Stripe JavaScript API, and the react-stripe-js
library contains the required frontend elements as React components.
In the App.js
file, initialize Stripe by using the loadStripe()
function.
1import { loadStripe } from "@stripe/stripe-js";
2
3const stripePromise = loadStripe(STRIPE_PUBLISHABLE_KEY);
In the loadStripe()
function, pass your Stripe publishable key, which you can get from your Stripe dashboard. The function will return a promise
that you need to pass to the <Elements />
wrapper component.
The <Elements />
wrapper component is a provider that allows you to access a Stripe object in any of the nested components. You should wrap the card input form in the <Elements />
component.
The loadStripe()
function is asynchronous and loads the stripe-js
script with the Stripe object.
1// ...
2import { Elements } from "@stripe/react-stripe-js";
3import { loadStripe } from "@stripe/stripe-js";
4
5const stripePromise = loadStripe(STRIPE_PUBLISHABLE_KEY);
6
7const App = () => {
8 return (
9 <div className="App">
10 <div className="product">
11 <img
12 src="https://images.pexels.com/photos/18105/pexels-photo.jpg?auto=compress"
13 alt="laptop"
14 style={{ width: "100%", height: "auto" }}
15 />
16 <div>
17 <Elements stripe={stripePromise}>
18 <CheckoutForm />
19 </Elements>
20 </div>
21 </div>
22 </div>
23 );
24};
25// ...
Inside the
1import { CardElement } from "@stripe/react-stripe-js";
2
3const CARD_ELEMENT_OPTIONS = {
4 iconStyle: "solid",
5 hidePostalCode: true,
6 style: {
7 base: {
8 iconColor: "rgb(240, 57, 122)",
9 color: "rgb(240, 57, 122)",
10 fontSize: "16px",
11 fontFamily: '"Open Sans", sans-serif',
12 fontSmoothing: "antialiased",
13 "::placeholder": {
14 color: "#CFD7DF"
15 }
16 },
17 invalid: {
18 color: "#e5424d",
19 ":focus": {
20 color: "#303238"
21 }
22 }
23 }
24};
25
26function CardSection() {
27 return <CardElement options={CARD_ELEMENT_OPTIONS} />;
28}
Add the <CardSection />
component inside the <CheckoutForm />
.
The <CheckoutForm />
component contains product details, and the <CardSection />
component accepts the user's card details.
1import { ElementsConsumer, CardElement } from "@stripe/react-stripe-js";
2
3class CheckoutForm extends React.Component {
4 handleSubmit = async event => {
5 event.preventDefault();
6
7 // handle payment request
8 };
9
10 render() {
11 return (
12 <div>
13 <div class="product-info">
14 <h3 className="product-title">Apple MacBook Pro</h3>
15 <h4 className="product-price">$999</h4>
16 </div>
17 <form onSubmit={this.handleSubmit}>
18 <CardSection />
19 <button className="btn-pay">Buy Now</button>
20 </form>
21 </div>
22 );
23 }
24}
Wrap the <Checkout />
form component with the <ElementsConsumer />
component to get access to the Stripe object. The <ElementsConsumer />
component safely passes the payment information collected by the card element. Pass the properties stripe
and elements
of the Stripe object to the <CheckoutForm />
.
1function InjectedCheckoutForm() {
2 return (
3 <ElementsConsumer>
4 {({ stripe, elements }) => (
5 <CheckoutForm stripe={stripe} elements={elements} />
6 )}
7 </ElementsConsumer>
8 );
9}
Now, in the handleSubmit
method, first check if Stripe is initialized or not. If it is, get the card details from the elements
prop and pass them to the createToken()
function of the stripe
prop.
1handleSubmit = async event => {
2 event.preventDefault();
3
4 const { stripe, elements } = this.props;
5 if (!stripe || !elements) {
6 return;
7 }
8
9 const card = elements.getElement(CardElement);
10 const result = await stripe.createToken(card);
11 if (result.error) {
12 console.log(result.error.message);
13 } else {
14 console.log(result.token);
15 // pass the token to your backend API
16 }
17};
Stripe will create a token that represents the user's card details. This process is called tokenization.
Once you have the token
object, call your backend API service to process the payment.
Following is a sample Node.js
code to guide you through it.
1const stripe = require('stripe')(STRIPE_SECRET_KEY);
2
3// get the product details
4const product = getTheProduct(productId);
5
6stripe.charges.create(
7 {
8 amount: product.price,
9 currency: 'usd',
10 source: cardToken.id,
11 description: `Payment for ${product.title}`,
12 metadta: {
13 productId: product.id
14 }
15 },
16 function(err, charge) {
17 if(err) new Error("Payment Failed");
18 else console.log("Payment Success");
19 }
Once you get a successful response from the Stripe server, send the response back to your client application and show a success message.
Here is the entire code for your reference.
1import React from "react";
2import "./styles.css";
3import { Elements } from "@stripe/react-stripe-js";
4import { loadStripe } from "@stripe/stripe-js";
5import CheckoutForm from "./CheckoutForm";
6
7const stripePromise = loadStripe("pk_test_35p114pH8oNuHX72SmrvsFqh00Azv3ZaIA");
8
9const App = () => {
10 return (
11 <div className="App">
12 <div className="product">
13 <img
14 src="https://images.pexels.com/photos/18105/pexels-photo.jpg?auto=compress"
15 alt="laptop"
16 style={{ width: "100%", height: "auto" }}
17 />
18 <div>
19 <Elements stripe={stripePromise}>
20 <CheckoutForm />
21 </Elements>
22 </div>
23 </div>
24 </div>
25 );
26};
27
28export default App;
1import React from "react";
2import { ElementsConsumer, CardElement } from "@stripe/react-stripe-js";
3
4import CardSection from "./CardSection";
5
6class CheckoutForm extends React.Component {
7 handleSubmit = async event => {
8 event.preventDefault();
9
10 const { stripe, elements } = this.props;
11 if (!stripe || !elements) {
12 return;
13 }
14
15 const card = elements.getElement(CardElement);
16 const result = await stripe.createToken(card);
17 if (result.error) {
18 console.log(result.error.message);
19 } else {
20 console.log(result.token);
21 }
22 };
23
24 render() {
25 return (
26 <div>
27 <div class="product-info">
28 <h3 className="product-title">Apple MacBook Pro</h3>
29 <h4 className="product-price">$999</h4>
30 </div>
31 <form onSubmit={this.handleSubmit}>
32 <CardSection />
33 <button disabled={!this.props.stripe} className="btn-pay">
34 Buy Now
35 </button>
36 </form>
37 </div>
38 );
39 }
40}
41
42export default function InjectedCheckoutForm() {
43 return (
44 <ElementsConsumer>
45 {({ stripe, elements }) => (
46 <CheckoutForm stripe={stripe} elements={elements} />
47 )}
48 </ElementsConsumer>
49 );
50}
1import React from "react";
2import { CardElement } from "@stripe/react-stripe-js";
3
4const CARD_ELEMENT_OPTIONS = {
5 style: {
6 base: {
7 color: "#303238",
8 fontSize: "16px",
9 fontFamily: "sans-serif",
10 fontSmoothing: "antialiased",
11 "::placeholder": {
12 color: "#CFD7DF"
13 }
14 },
15 invalid: {
16 color: "#e5424d",
17 ":focus": {
18 color: "#303238"
19 }
20 }
21 }
22};
23
24function CardSection() {
25 return (
26 <label>
27 Card details
28 <CardElement options={CARD_ELEMENT_OPTIONS} />
29 </label>
30 );
31}
32
33export default CardSection;
1import React from "react";
2import ReactDOM from "react-dom";
3
4import App from "./App";
5
6const rootElement = document.getElementById("root");
7ReactDOM.render(
8 <React.StrictMode>
9 <App />
10 </React.StrictMode>,
11 rootElement
12);
1body {
2 margin: 0;
3 padding: 0;
4}
5
6.App {
7 font-family: sans-serif;
8 height: 100vh;
9 display: flex;
10 align-items: center;
11}
12
13.StripeElement {
14 margin: 15px auto;
15 padding: 10px 12px;
16 color: #32325d;
17 background-color: white;
18 border: 1px solid transparent;
19 border-radius: 4px;
20}
21
22.StripeElement--webkit-autofill {
23 background-color: #fefde5 !important;
24}
25
26.product {
27 width: 100%;
28 max-width: 450px;
29 margin: auto;
30 box-shadow: 0px 15px 30px rgba(0, 0, 0, 0.4);
31 border-radius: 10px;
32 overflow: hidden;
33}
34
35.btn-pay {
36 display: block;
37 width: 100%;
38 border: none;
39 background: linear-gradient(
40 135deg,
41 rgb(49, 0, 62) 0%,
42 rgb(195, 40, 110) 100%
43 );
44 color: #fff;
45 padding: 10px;
46 font-size: 18px;
47 cursor: pointer;
48}
49
50.product-info {
51 padding: 0 16px;
52}
53
54h3.product-title {
55 font-size: 28px;
56 margin-bottom: 15px;
57}
58
59h4.product-price {
60 font-size: 24px;
61 margin: 0;
62 margin-bottom: 30px;
63 color: #777;
64 font-weight: 500;
65}
Integrating payment gateways into web applications is an essential skill to have as a developer now that so many businesses accept payment online. With Stripe's client and server-side libraries, you can create robust and secure applications that are PCI-compliant. Always remember to never pass card details to your server as it violates PCI guidelines.
I hope this was a fun and great learning opportunity for you to understand online payment gateways. This is just the beginning. There are many more complex concepts, like handling subscriptions with Stripe, that you can look into for further learning.