Author avatar

Gaurav Singhal

How to Integrate Stripe with React

Gaurav Singhal

  • Apr 3, 2020
  • 12 Min read
  • 22,406 Views
  • Apr 3, 2020
  • 12 Min read
  • 22,406 Views
Web Development
Front End Web Development
Server-Side Frameworks
React

Introduction

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.

final result

Payment Flow

The complete payment processing flow is described below:

  1. The user enters details into the card form.

  2. The client application sends the card details to the Stripe API.

  3. The Stripe API performs tokenization and returns a token object for the card.

  4. The client application sends the card token to the backend application with other data related to the purchase.

  5. The backend application makes the payment request with the card token and amount details to the Stripe API.

tokenized payment flow

Bootstrapping the Application

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};
jsx

Installing and Initializing the Stripe Libraries

You need to install two Stripe libraries to get started with the integration.

1npm i @stripe/stripe-js @stripe/react-stripe-js
console

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);
jsx

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// ...
jsx

The <CardSection /> Component

Inside the component, render the component from the Stripe library. The component securely accepts and stores the card details entered by the user. It is completely customizable in terms of styling so that you can easily embed it in your application without having to worry about the overall theme. For more details on options, check out this link.

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}
jsx

Add the <CardSection /> component inside the <CheckoutForm />.

The <CheckoutForm /> Component

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}
jsx

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}
jsx

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};
jsx

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  }
js

Once you get a successful response from the Stripe server, send the response back to your client application and show a success message.

Complete Source Code

Here is the entire code for your reference.

App.js

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;
jsx

CheckoutForm.js

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}
jsx

CardSection.js

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;
jsx

index.js

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);
jsx

styles.css

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}
css

Conclusion

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.