Author avatar

Gaurav Singhal

How to Integrate Stripe with React

Gaurav Singhal

  • Apr 3, 2020
  • 12 Min read
  • 7,504 Views
  • Apr 3, 2020
  • 12 Min read
  • 7,504 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.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const App = () => {
  return (
    <div className="App">
      <div className="product">
        <img
          src="https://images.pexels.com/photos/18105/pexels-photo.jpg?auto=compress"
          alt="laptop"
          style={{ width: "100%", height: "auto" }}
        />
        <div>
          {
            // Checkout component
          }
        </div>
      </div>
    </div>
  );
};
jsx

Installing and Initializing the Stripe Libraries

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

1
npm 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.

1
2
3
import { loadStripe } from "@stripe/stripe-js";

const 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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// ...
import { Elements } from "@stripe/react-stripe-js";
import { loadStripe } from "@stripe/stripe-js";

const stripePromise = loadStripe(STRIPE_PUBLISHABLE_KEY);

const App = () => {
  return (
    <div className="App">
      <div className="product">
        <img
          src="https://images.pexels.com/photos/18105/pexels-photo.jpg?auto=compress"
          alt="laptop"
          style={{ width: "100%", height: "auto" }}
        />
        <div>
          <Elements stripe={stripePromise}>
            <CheckoutForm />
          </Elements>
        </div>
      </div>
    </div>
  );
};
// ...
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.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import { CardElement } from "@stripe/react-stripe-js";

const CARD_ELEMENT_OPTIONS = {
  iconStyle: "solid",
  hidePostalCode: true,
  style: {
    base: {
      iconColor: "rgb(240, 57, 122)",
      color: "rgb(240, 57, 122)",
      fontSize: "16px",
      fontFamily: '"Open Sans", sans-serif',
      fontSmoothing: "antialiased",
      "::placeholder": {
        color: "#CFD7DF"
      }
    },
    invalid: {
      color: "#e5424d",
      ":focus": {
        color: "#303238"
      }
    }
  }
};

function CardSection() {
  return <CardElement options={CARD_ELEMENT_OPTIONS} />;
}
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.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import { ElementsConsumer, CardElement } from "@stripe/react-stripe-js";

class CheckoutForm extends React.Component {
  handleSubmit = async event => {
    event.preventDefault();

    // handle payment request
  };

  render() {
    return (
      <div>
        <div class="product-info">
          <h3 className="product-title">Apple MacBook Pro</h3>
          <h4 className="product-price">$999</h4>
        </div>
        <form onSubmit={this.handleSubmit}>
          <CardSection />
          <button className="btn-pay">Buy Now</button>
        </form>
      </div>
    );
  }
}
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 />.

1
2
3
4
5
6
7
8
9
function InjectedCheckoutForm() {
  return (
    <ElementsConsumer>
      {({ stripe, elements }) => (
        <CheckoutForm stripe={stripe} elements={elements} />
      )}
    </ElementsConsumer>
  );
}
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.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
handleSubmit = async event => {
  event.preventDefault();

  const { stripe, elements } = this.props;
  if (!stripe || !elements) {
    return;
  }

  const card = elements.getElement(CardElement);
  const result = await stripe.createToken(card);
  if (result.error) {
    console.log(result.error.message);
  } else {
    console.log(result.token);
    // pass the token to your backend API
  }
};
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.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
const stripe = require('stripe')(STRIPE_SECRET_KEY);

// get the product details
const product = getTheProduct(productId);

stripe.charges.create(
  {
    amount: product.price,
    currency: 'usd',
    source: cardToken.id,
    description: `Payment for ${product.title}`,
    metadta: {
      productId: product.id
    }
  },
  function(err, charge) {
    if(err) new Error("Payment Failed");
    else console.log("Payment Success");
  }
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import React from "react";
import "./styles.css";
import { Elements } from "@stripe/react-stripe-js";
import { loadStripe } from "@stripe/stripe-js";
import CheckoutForm from "./CheckoutForm";

const stripePromise = loadStripe("pk_test_35p114pH8oNuHX72SmrvsFqh00Azv3ZaIA");

const App = () => {
  return (
    <div className="App">
      <div className="product">
        <img
          src="https://images.pexels.com/photos/18105/pexels-photo.jpg?auto=compress"
          alt="laptop"
          style={{ width: "100%", height: "auto" }}
        />
        <div>
          <Elements stripe={stripePromise}>
            <CheckoutForm />
          </Elements>
        </div>
      </div>
    </div>
  );
};

export default App;
jsx

CheckoutForm.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
import React from "react";
import { ElementsConsumer, CardElement } from "@stripe/react-stripe-js";

import CardSection from "./CardSection";

class CheckoutForm extends React.Component {
  handleSubmit = async event => {
    event.preventDefault();

    const { stripe, elements } = this.props;
    if (!stripe || !elements) {
      return;
    }

    const card = elements.getElement(CardElement);
    const result = await stripe.createToken(card);
    if (result.error) {
      console.log(result.error.message);
    } else {
      console.log(result.token);
    }
  };

  render() {
    return (
      <div>
        <div class="product-info">
          <h3 className="product-title">Apple MacBook Pro</h3>
          <h4 className="product-price">$999</h4>
        </div>
        <form onSubmit={this.handleSubmit}>
          <CardSection />
          <button disabled={!this.props.stripe} className="btn-pay">
            Buy Now
          </button>
        </form>
      </div>
    );
  }
}

export default function InjectedCheckoutForm() {
  return (
    <ElementsConsumer>
      {({ stripe, elements }) => (
        <CheckoutForm stripe={stripe} elements={elements} />
      )}
    </ElementsConsumer>
  );
}
jsx

CardSection.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import React from "react";
import { CardElement } from "@stripe/react-stripe-js";

const CARD_ELEMENT_OPTIONS = {
  style: {
    base: {
      color: "#303238",
      fontSize: "16px",
      fontFamily: "sans-serif",
      fontSmoothing: "antialiased",
      "::placeholder": {
        color: "#CFD7DF"
      }
    },
    invalid: {
      color: "#e5424d",
      ":focus": {
        color: "#303238"
      }
    }
  }
};

function CardSection() {
  return (
    <label>
      Card details
      <CardElement options={CARD_ELEMENT_OPTIONS} />
    </label>
  );
}

export default CardSection;
jsx

index.js

1
2
3
4
5
6
7
8
9
10
11
12
import React from "react";
import ReactDOM from "react-dom";

import App from "./App";

const rootElement = document.getElementById("root");
ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  rootElement
);
jsx

styles.css

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
body {
  margin: 0;
  padding: 0;
}

.App {
  font-family: sans-serif;
  height: 100vh;
  display: flex;
  align-items: center;
}

.StripeElement {
  margin: 15px auto;
  padding: 10px 12px;
  color: #32325d;
  background-color: white;
  border: 1px solid transparent;
  border-radius: 4px;
}

.StripeElement--webkit-autofill {
  background-color: #fefde5 !important;
}

.product {
  width: 100%;
  max-width: 450px;
  margin: auto;
  box-shadow: 0px 15px 30px rgba(0, 0, 0, 0.4);
  border-radius: 10px;
  overflow: hidden;
}

.btn-pay {
  display: block;
  width: 100%;
  border: none;
  background: linear-gradient(
    135deg,
    rgb(49, 0, 62) 0%,
    rgb(195, 40, 110) 100%
  );
  color: #fff;
  padding: 10px;
  font-size: 18px;
  cursor: pointer;
}

.product-info {
  padding: 0 16px;
}

h3.product-title {
  font-size: 28px;
  margin-bottom: 15px;
}

h4.product-price {
  font-size: 24px;
  margin: 0;
  margin-bottom: 30px;
  color: #777;
  font-weight: 500;
}
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.

64