How to Build a Stripe React Payment Form
We'll continue from what we've done in the previous lesson by looking to capture a user's credit or debit card information when a booking is to be made, with the help of the React Stripe Elements library.
Get the project source code below, and follow along with the lesson material.
Download Project Source CodeTo set up the project on your local machine, please follow the directions provided in the README.md
file. If you run into any issues with running the project source code, then feel free to reach out to the author in the course's Discord channel.
This lesson preview is part of the TinyHouse: A Fullstack React Masterclass with TypeScript and GraphQL - Part Two course and can be unlocked immediately with a single-time purchase. Already have access to this course? Log in here.
Get unlimited access to TinyHouse: A Fullstack React Masterclass with TypeScript and GraphQL - Part Two, plus 70+ \newline books, guides and courses with the \newline Pro subscription.
[00:00 - 00:23] With a listing booking modal now presented and shown to a user that attempts to request a booking, let's now work on presenting the elements where we'll be able to capture a user 's credit or debit card information. We've mentioned before how Stripe provides their own Stripe elements, which are UI components that help capture payment information from users.
[00:24 - 00:43] Stripe elements provides many different UI elements to capture debits credit card information, Apple Pay capability, bank information and so on. In our app, we're only going to be accepting debit or credit card information, so we'll be interested in only showing the card elements from Stripe.
[00:44 - 00:56] Now, these Stripe elements examples are often shown with normal HTML CSS and JavaScript. However, the Stripe documentation does offer a React component alternative that we'll be using.
[00:57 - 01:09] We'll be linking these documents in the lesson manuscript. And for now, let's go through the steps they have highlighted in this using Stripe elements in React documentation.
[01:10 - 01:27] They first tell us that we'll need to set up a project with which we've already done, but we'll need to install the React Stripe elements library. When installed, we're told to add a script tag in the index HTML file of our public folder to load the Stripe library.
[01:28 - 01:34] Why? This is for PCI, which stands for Payment Card Industry Compliance.
[01:35 - 01:49] We're told we must load Stripe directly from Stripe servers at runtime and not install it for NPM or as an app dependency. The next step that's given to us is to create the payment for.
[01:50 - 02:02] The React Stripe elements library gives us a card elements component and an inject Stripe higher order function. The card element component is literally the card elements we'll want to show the user.
[02:03 - 02:23] The inject Stripe function allows us to create a higher order component that provides an injected Stripe prop, which contains a Stripe object we'll need to access. We're then also told that in the uppermost parent's components, we should have our app contained within a Stripe provider.
[02:24 - 02:39] Stripe provider initializes Stripe and accepts an API key with which we'll pass in the publishable key of our Stripe accounts. And then we can use the elements component to wrap the payment form.
[02:40 - 02:59] The documentation tells us that this elements component is to wrap the parent that is to contain the different Stripe components we can create. In our application, we're only going to have a single card element component from Stripe with which we'll have these elements be wrapped as a parent.
[03:00 - 03:28] Finally, when a payment is made from the client, we can retrieve the token information from the injected Stripe object prop with which the ID will be the source information that will pass into our server from our client to dictate the payment source that was made. And the rest of the documentation talks about how in the server we can conduct a charge, but we've already done this before.
[03:29 - 03:32] So there's a decent amount of things we need to do. So we'll do them step by step.
[03:33 - 03:59] First, let's install the React Stripe Elements library in our client application. We'll also install the community prepared typings from the definitely typed repository.
[04:00 - 04:17] We'll then head over to the public index.html file to load the Stripe library directly from Stripe servers. We'll declare a script tag that has a source of HTTPS.js.stripe.com/v3.
[04:18 - 04:44] And this is from the Stripe documentation. In our root level sections index file, we'll import the Stripe provider and elements components from the React Stripe Elements library.
[04:45 - 05:08] In the return statement for our parent app component, we'll wrap our entire app with the Stripe provider component to have Stripe available everywhere. For the API key prop, we'll provide the value of the React app's publishable key environment variable we have in our client project.
[05:09 - 05:21] And we introduced this environment key when we got started with our Stripe account. TypeScript will warn us that the API key prop should be a string and this environment variable can either be a string or undefined.
[05:22 - 05:35] In this case, we'll assume that when our app starts, this key will always be available as a string from the environment configuration. So with that said, we'll cast the type as a string.
[05:36 - 05:50] We've mentioned how the elements component we're importing from React Stripe Elements should be the parent of all the Stripe elements we'll want to display. We're only going to display our Stripe element within the listing section component.
[05:51 - 06:19] So what we can do is we can wrap this listing component rendered in the listing route with elements. And now we'll head over to the listing create booking modal component file and we'll import the two things we'll need from React Stripe Elements, the card element and the inject stripe higher order function.
[06:20 - 06:50] At the bottom of this file, we'll create an export a new constant called wrapped listing create booking modal that is to reference the higher order component and we'll use the inject stripe function and place the listing create booking modal component within. So now at this moment, our listing create booking modal component will be the result of a higher order component that is to receive a stripe object prop.
[06:51 - 07:20] To help define the shape of this object prop will import the react stripe elements namespace available from the typings of the react stripe elements library. Now, note that react stripe elements isn't an interface of its own, but instead a name space, which in TypeScript is a good way to basically organize internal modules and help organize the types and interfaces within the module.
[07:21 - 07:49] So within this react stripe elements namespace, there exists an interface called injected stripe props, which is the object interface that indicates the type of the stripe object available in our component. So in our components, we'll declare that the stripe prop is to be available and we'll say the shape of all our props are props and react stripe elements dot injected stripe props.
[07:50 - 08:07] And now when we take a look at the stripe object prop, we'll see it is to have a type associated with it. Within the return statement of our modal in the section where we display the primary button, we'll place the card elements component from stripe right above the button.
[08:08 - 08:18] And though there's customizations we could do, we're not going to do a lot of different changes. The one thing we'll do is we'll just hide the postal code from our form by using the hide postal code prop.
[08:19 - 08:37] The reason being is in our use case, we don't plan on capturing a user's postal code in our payments form. And at this moment, we'll need to ensure that we're going to import the higher order component.
[08:38 - 08:54] So in the listing component, we'll import wrapped listing create booking model as listing create booking model. So let's see how this would now look like.
[08:55 - 09:08] We'll head back to our application in the listing page. We'll select to check in dates and a check out date and then click the request a book button and we'll be presented with the stripe card element.
[09:09 - 09:25] Notice that this card element is requesting the card number, the expiry date and the three digits CVC code, the back of the card. Now the best part about this is this particular element is expecting valid payment information.
[09:26 - 09:39] So if I was to type just an obscure number of numbers here, it would recognize that this is an invalid card. If I was to type an expiry date in the past, it would recognize that this is an invalid expiry date.
[09:40 - 09:43] Amazing. Now, keep in mind that we're still in the testing environment.
[09:44 - 09:52] So is stripe payments documentation that we'll share in the lesson manuscript? That tells us that genuine card information cannot be used in test mode.
[09:53 - 10:07] Instead, we can use a large list of valid test card numbers. So in this particular case, we'll take the very first result here, which is going to mimic a visa card and we'll simply do 4, 2, 4, 2, 4, 2, 4, 2.
[10:08 - 10:17] The expiry time could be any future dates. So we can set something like 01, 22 and the CVC could be any three digits, 7, 4 , 4.
[10:18 - 10:33] So at this very moment, this element tells us or recognizes that this is a valid visa credit card. And if I was to click the book button and we had the mutation wired, this would actually ensure that we're specifying that a correct card has been used.
[10:34 - 10:45] So what are we interested in sort of happening where we actually click the book button? We know that the create booking mutation will be created, but is there anything else we need to sort of recognize and understand from this payment form?
[10:46 - 10:57] Well, the stripe payments testing page actually gives us some information on what we should be looking for. And we are particularly interested in the charges API because we actually run the charge functionality on the server.
[10:58 - 11:07] And it tells us that doing testing, ensure that the card element is passed correctly to create token. We're going to run this function right now and we'll show you what it is.
[11:08 - 11:16] But essentially, it would give us the token of the stripe information. And in the response handler, if there's any card errors, make sure you handle it and display it properly.
[11:17 - 11:34] And then only if valid tokens exist, then pass them to the server as part of the payment form submission. So with that said, without building out the create booking mutation just yet, let's try and get this token information from this payment element.
[11:35 - 11:44] So we'll head back to our code. And in the listing, create booking model components in the button that would actually trigger the booking functionality.
[11:45 - 11:54] Let's attach an on click prop. That is to call a function will create called handle creates booking.
[11:55 - 12:04] We'll create this function above. It will be an asynchronous function.
[12:05 - 12:20] And the first thing we can check for this function is to see if this injected stripe object actually exists. The reason being is that the typings of the react stripe elements library tells us that this stripe object could either have a type associated with it or it could be undefined.
[12:21 - 12:29] So in our case, we'll say if this for some reason doesn't exist, we can display an error of sorts later. But for now, we'll just return early.
[12:30 - 12:51] If it does exist, the moment that this payment is made and the user actually wants to create the booking, what we can do is we can actually run the create token function within an error in this stripe object. And this create token function will give us the token from our actual stripe object.
[12:52 - 13:05] And in this case, why don't we provide a different name to this token to be more explicit and we'll say stripe token. And at this moment, let's just simply place a console lock and try to see what this token will look like.
[13:06 - 13:23] We can head back to our app. We'll select some dates again, provide a valid test credit card information.
[13:24 - 13:39] And we'll do the one we've done before, which was a valid test example of a visa card for 24242 all the way through. And now if I click book at this very moment, the request and the create token function would run very briefly.
[13:40 - 13:50] And when it completes, we'll get information about the payment source that was provided. In this particular context, I have information that a card was used.
[13:51 - 14:05] I have a live mode field, which even knows that we're doing this within test mode. And within this card object, we have information about the payment mate, brand visa country US, the idea of this card is this funding is credit.
[14:06 - 14:15] The last four digits are 4242. And if our payment information was to accept postal code or address information , we'll also get this information here.
[14:16 - 14:28] So depending on one's or a person's use case, this information could be valuable depending on what one wants to do. But in our case, what we want to capture is simply the ID of the actual token that exists.
[14:29 - 14:35] And this ID is going to be the source of the payment. Or in other words, it's going to represent the source of the payment.
[14:36 - 14:44] And we're going to pass this onto our server as the source field of our actual mutation. Great.
[14:45 - 14:59] We'll look to finish off our actual request here in the next lesson where we'll conduct the mutation and we'll take this ID and pass it as source and handle any potential client errors that may come up. However, before we close in this lesson, there's a few things we can talk about .
[15:00 - 15:26] At this moment, if I was to simply refresh my app and take a look at my console , I'll see that there's a few console messages that I've been shown by simply introducing the Stripe Content Delivery Network in our public index file. One of the messages we see is actually that tells us that we may test our Stri pe JS integration over HTTP, however, live Stripe integrations must use HTTPS.
[15:27 - 15:28] This is good. This makes sense.
[15:29 - 15:43] Obviously, in our local development environment, it's an HTTP and it tells us that we can test our integration. But when we actually deploy our app, we'll ensure that it's an HTTPS and then we'll basically specify that we can check out our live Stripe integration.
[15:44 - 16:00] So another message that does come up and it tells us that a cookie associated with a cross-side resource was set without the same set attributes, etc, etc, etc. Now this doesn't come from the React Stripe Elements library, but it comes from actually trying to load the Stripe JavaScript file in a public index HTML file.
[16:01 - 16:05] There's nothing else we can do here. That's pretty much Stripe's responsibility.
[16:06 - 16:16] And there is an open issue within the Stripe documentation that highlights they 're looking to resolve this for the Chrome browser sooner than later. So depending on when you actually try this out, you may see this issue.
[16:17 - 16:25] If you do, not a particular concern, this is nothing from our end. If you don't see this issue or you don't see this warning, it probably means that the Stripe team has handled it.
[16:26 - 16:43] The other thing we will mention before we close is you'll notice that in our code, we've used the inject Stripe higher order components to provide the Stripe prop object. And like we've seen before and we've mentioned that with React, things are moving closer to hooks as opposed to higher order components.
[16:44 - 17:04] The Stripe documentation and at this very moment when the screencast was actually recorded, doesn't provide any alternative to using a hook, which is why we're using the actual higher order component. If you do search up React Stripe Elements hooks, there are open get up issues at this very moment where the community is discussing different ways of how to create their own custom hooks.
[17:05 - 17:10] You're more than welcome to create it and give it a try. But in our case, we're going to keep this as formal as possible.
[17:11 - 17:13] Awesome. Great job so far in the next lesson.
[17:14 - 17:18] We'll look to finalize what we've done here and actually trigger the mutation and conduct the payment.