1 | ## We’ve moved to [@stripe/react-stripe-js](https://github.com/stripe/react-stripe-js)!
|
2 |
|
3 | We have decided to rename, rework, and move this project. We have no plans for
|
4 | any additional major releases of `react-stripe-elements`.
|
5 |
|
6 | If you are starting a new Stripe integration or are looking to update your
|
7 | existing integration, use
|
8 | [React Stripe.js](https://github.com/stripe/react-stripe-js).
|
9 |
|
10 | - [Learn to accept a payment (with React Stripe.js!)](https://stripe.com/docs/payments/accept-a-payment#web)
|
11 | - [Migrate from `react-stripe-elements` to React Stripe.js](https://github.com/stripe/react-stripe-js/blob/master/docs/migrating.md)
|
12 |
|
13 | ---
|
14 |
|
15 | # react-stripe-elements
|
16 |
|
17 | [![build status](https://img.shields.io/travis/stripe/react-stripe-elements/master.svg?style=flat-square)](https://travis-ci.org/stripe/react-stripe-elements)
|
18 | [![npm version](https://img.shields.io/npm/v/react-stripe-elements.svg?style=flat-square)](https://www.npmjs.com/package/react-stripe-elements)
|
19 |
|
20 | > React components for Stripe.js and Stripe Elements
|
21 |
|
22 | This project is a thin React wrapper around
|
23 | [Stripe.js](https://stripe.com/docs/stripe.js) and
|
24 | [Stripe Elements](https://stripe.com/docs/elements). It allows you to add
|
25 | Elements to any React app, and manages the state and lifecycle of Elements for
|
26 | you.
|
27 |
|
28 | The
|
29 | [Stripe.js / Stripe Elements API reference](https://stripe.com/docs/elements/reference)
|
30 | goes into more detail on the various customization options for Elements (e.g.
|
31 | styles, fonts).
|
32 |
|
33 |
|
34 |
|
35 |
|
36 | ## Table of Contents
|
37 |
|
38 | - [Demo](#demo)
|
39 | - [Installation](#installation)
|
40 | - [First, install `react-stripe-elements`.](#first-install-react-stripe-elements)
|
41 | - [Then, load Stripe.js in your application:](#then-load-stripejs-in-your-application)
|
42 | - [Getting started](#getting-started)
|
43 | - [The Stripe context (`StripeProvider`)](#the-stripe-context-stripeprovider)
|
44 | - [Element groups (`Elements`)](#element-groups-elements)
|
45 | - [Setting up your payment form (`injectStripe`)](#setting-up-your-payment-form-injectstripe)
|
46 | - [Using individual `*Element` components](#using-individual-element-components)
|
47 | - [Using the `PaymentRequestButtonElement`](#using-the-paymentrequestbuttonelement)
|
48 | - [Advanced integrations](#advanced-integrations)
|
49 | - [Loading Stripe.js asynchronously](#loading-stripejs-asynchronously)
|
50 | - [Server-side rendering (SSR)](#server-side-rendering-ssr)
|
51 | - [Using an existing Stripe instance](#using-an-existing-stripe-instance)
|
52 | - [Component reference](#component-reference)
|
53 | - [`<StripeProvider>`](#stripeprovider)
|
54 | - [Props shape](#props-shape)
|
55 | - [`<Elements>`](#elements)
|
56 | - [Props shape](#props-shape-1)
|
57 | - [`<*Element>` components](#element-components)
|
58 | - [Available components](#available-components)
|
59 | - [Props shape](#props-shape-2)
|
60 | - [Using `onReady`](#using-onready)
|
61 | - [`injectStripe` HOC](#injectstripe-hoc)
|
62 | - [Example](#example)
|
63 | - [Troubleshooting](#troubleshooting)
|
64 | - [Development](#development)
|
65 |
|
66 |
|
67 |
|
68 |
|
69 | ## Demo
|
70 |
|
71 | The fastest way to start playing around with `react-stripe-elements` is with
|
72 | this JSFiddle: <https://jsfiddle.net/f5wxprnc/>.
|
73 |
|
74 | You can also play around with the demo locally. The source code is in
|
75 | [demo/](demo/). To run it:
|
76 |
|
77 | ```shell
|
78 | git clone https://github.com/stripe/react-stripe-elements
|
79 | cd react-stripe-elements
|
80 |
|
81 | # (make sure you have yarn installed: https://yarnpkg.com/)
|
82 |
|
83 | yarn install
|
84 | yarn run demo
|
85 | ```
|
86 |
|
87 | Now go to <http://localhost:8080/> to try it out!
|
88 |
|
89 | > :warning: `PaymentRequestButtonElement` will not render unless the page is
|
90 | > served over HTTPS. To demo `PaymentRequestButtonElement`, you can tunnel over
|
91 | > HTTPS to the local server using ngrok or a similar service.
|
92 |
|
93 | ![Screenshot of the demo running](demo/demo.png)
|
94 |
|
95 | ## Installation
|
96 |
|
97 | ### First, install `react-stripe-elements`.
|
98 |
|
99 | Install with `yarn`:
|
100 |
|
101 | ```
|
102 | yarn add react-stripe-elements
|
103 | ```
|
104 |
|
105 | OR with `npm`:
|
106 |
|
107 | ```
|
108 | npm install --save react-stripe-elements
|
109 | ```
|
110 |
|
111 | OR using UMD build (exports a global `ReactStripeElements` object);
|
112 |
|
113 | ```html
|
114 | <script src="https://unpkg.com/react-stripe-elements@latest/dist/react-stripe-elements.min.js"></script>
|
115 | ```
|
116 |
|
117 | ### Then, load Stripe.js in your application:
|
118 |
|
119 | ```html
|
120 | <script src="https://js.stripe.com/v3/"></script>
|
121 | ```
|
122 |
|
123 | ## Getting started
|
124 |
|
125 | ### The Stripe context (`StripeProvider`)
|
126 |
|
127 | In order for your application to have access to
|
128 | [the Stripe object](https://stripe.com/docs/elements/reference#the-stripe-object),
|
129 | let's add `StripeProvider` to our root React App component:
|
130 |
|
131 | ```jsx
|
132 | // index.js
|
133 | import React from 'react';
|
134 | import {render} from 'react-dom';
|
135 | import {StripeProvider} from 'react-stripe-elements';
|
136 |
|
137 | import MyStoreCheckout from './MyStoreCheckout';
|
138 |
|
139 | const App = () => {
|
140 | return (
|
141 | <StripeProvider apiKey="pk_test_12345">
|
142 | <MyStoreCheckout />
|
143 | </StripeProvider>
|
144 | );
|
145 | };
|
146 |
|
147 | render(<App />, document.getElementById('root'));
|
148 | ```
|
149 |
|
150 | ### Element groups (`Elements`)
|
151 |
|
152 | Next, when you're building components for your checkout form, you'll want to
|
153 | wrap the `Elements` component around your `form`. This groups the set of Stripe
|
154 | Elements you're using together, so that we're able to pull data from groups of
|
155 | Elements when you're tokenizing.
|
156 |
|
157 | ```jsx
|
158 | // MyStoreCheckout.js
|
159 | import React from 'react';
|
160 | import {Elements} from 'react-stripe-elements';
|
161 |
|
162 | import InjectedCheckoutForm from './CheckoutForm';
|
163 |
|
164 | class MyStoreCheckout extends React.Component {
|
165 | render() {
|
166 | return (
|
167 | <Elements>
|
168 | <InjectedCheckoutForm />
|
169 | </Elements>
|
170 | );
|
171 | }
|
172 | }
|
173 |
|
174 | export default MyStoreCheckout;
|
175 | ```
|
176 |
|
177 | ### Setting up your payment form (`injectStripe`)
|
178 |
|
179 | Use the `injectStripe` [Higher-Order Component][hoc] (HOC) to build your payment
|
180 | form components in the `Elements` tree. The [Higher-Order Component][hoc]
|
181 | pattern in React can be unfamiliar to those who've never seen it before, so
|
182 | consider reading up before continuing. The `injectStripe` HOC provides the
|
183 | `this.props.stripe` and `this.props.elements` properties that manage your
|
184 | `Elements` groups. Within an injected component, you can call any of the methods
|
185 | on the [Stripe][stripe] or [Elements][elements] objects.
|
186 |
|
187 | [hoc]: https://facebook.github.io/react/docs/higher-order-components.html
|
188 | [stripe]: https://stripe.com/docs/stripe-js/reference#the-stripe-object
|
189 | [elements]: https://stripe.com/docs/stripe-js/reference#the-elements-object
|
190 |
|
191 | > :warning: NOTE `injectStripe` cannot be used on the same element that renders
|
192 | > the `Elements` component; it must be used on the child component of
|
193 | > `Elements`. `injectStripe` _returns a wrapped component_ that needs to sit
|
194 | > under `<Elements>` but above any code where you'd like to access
|
195 | > `this.props.stripe`.
|
196 |
|
197 | ```jsx
|
198 | // CheckoutForm.js
|
199 | import React from 'react';
|
200 | import {injectStripe} from 'react-stripe-elements';
|
201 |
|
202 | import AddressSection from './AddressSection';
|
203 | import CardSection from './CardSection';
|
204 |
|
205 | class CheckoutForm extends React.Component {
|
206 | handleSubmit = (ev) => {
|
207 | // We don't want to let default form submission happen here, which would refresh the page.
|
208 | ev.preventDefault();
|
209 |
|
210 | // Use Elements to get a reference to the Card Element mounted somewhere
|
211 | // in your <Elements> tree. Elements will know how to find your Card Element
|
212 | // because only one is allowed.
|
213 | // See our getElement documentation for more:
|
214 | // https://stripe.com/docs/stripe-js/reference#elements-get-element
|
215 | const cardElement = this.props.elements.getElement('card');
|
216 |
|
217 | // From here we can call createPaymentMethod to create a PaymentMethod
|
218 | // See our createPaymentMethod documentation for more:
|
219 | // https://stripe.com/docs/stripe-js/reference#stripe-create-payment-method
|
220 | this.props.stripe
|
221 | .createPaymentMethod({
|
222 | type: 'card',
|
223 | card: cardElement,
|
224 | billing_details: {name: 'Jenny Rosen'},
|
225 | })
|
226 | .then(({paymentMethod}) => {
|
227 | console.log('Received Stripe PaymentMethod:', paymentMethod);
|
228 | });
|
229 |
|
230 | // You can also use confirmCardPayment with the PaymentIntents API automatic confirmation flow.
|
231 | // See our confirmCardPayment documentation for more:
|
232 | // https://stripe.com/docs/stripe-js/reference#stripe-confirm-card-payment
|
233 | this.props.stripe.confirmCardPayment('{PAYMENT_INTENT_CLIENT_SECRET}', {
|
234 | payment_method: {
|
235 | card: cardElement,
|
236 | },
|
237 | });
|
238 |
|
239 | // You can also use confirmCardSetup with the SetupIntents API.
|
240 | // See our confirmCardSetup documentation for more:
|
241 | // https://stripe.com/docs/stripe-js/reference#stripe-confirm-card-setup
|
242 | this.props.stripe.confirmCardSetup('{PAYMENT_INTENT_CLIENT_SECRET}', {
|
243 | payment_method: {
|
244 | card: cardElement,
|
245 | },
|
246 | });
|
247 |
|
248 | // You can also use createToken to create tokens.
|
249 | // See our tokens documentation for more:
|
250 | // https://stripe.com/docs/stripe-js/reference#stripe-create-token
|
251 | // With createToken, you will not need to pass in the reference to
|
252 | // the Element. It will be inferred automatically.
|
253 | this.props.stripe.createToken({type: 'card', name: 'Jenny Rosen'});
|
254 | // token type can optionally be inferred if there is only one Element
|
255 | // with which to create tokens
|
256 | // this.props.stripe.createToken({name: 'Jenny Rosen'});
|
257 |
|
258 | // You can also use createSource to create Sources.
|
259 | // See our Sources documentation for more:
|
260 | // https://stripe.com/docs/stripe-js/reference#stripe-create-source
|
261 | // With createSource, you will not need to pass in the reference to
|
262 | // the Element. It will be inferred automatically.
|
263 | this.props.stripe.createSource({
|
264 | type: 'card',
|
265 | owner: {
|
266 | name: 'Jenny Rosen',
|
267 | },
|
268 | });
|
269 | };
|
270 |
|
271 | render() {
|
272 | return (
|
273 | <form onSubmit={this.handleSubmit}>
|
274 | <AddressSection />
|
275 | <CardSection />
|
276 | <button>Confirm order</button>
|
277 | </form>
|
278 | );
|
279 | }
|
280 | }
|
281 |
|
282 | export default injectStripe(CheckoutForm);
|
283 | ```
|
284 |
|
285 | ### Using individual `*Element` components
|
286 |
|
287 | Now, you can use individual `*Element` components, such as `CardElement`, to
|
288 | build your form.
|
289 |
|
290 | ```jsx
|
291 | // CardSection.js
|
292 | import React from 'react';
|
293 | import {CardElement} from 'react-stripe-elements';
|
294 |
|
295 | class CardSection extends React.Component {
|
296 | render() {
|
297 | return (
|
298 | <label>
|
299 | Card details
|
300 | <CardElement style={{base: {fontSize: '18px'}}} />
|
301 | </label>
|
302 | );
|
303 | }
|
304 | }
|
305 |
|
306 | export default CardSection;
|
307 | ```
|
308 |
|
309 | ### Using the `PaymentRequestButtonElement`
|
310 |
|
311 | The
|
312 | [Payment Request Button](https://stripe.com/docs/elements/payment-request-button)
|
313 | lets you collect payment and address information from your customers using Apple
|
314 | Pay and the Payment Request API.
|
315 |
|
316 | To use the `PaymentRequestButtonElement` you need to first create a
|
317 | [`PaymentRequest` object](https://stripe.com/docs/stripe.js#the-payment-request-object).
|
318 | You can then conditionally render the `PaymentRequestButtonElement` based on the
|
319 | result of `paymentRequest.canMakePayment` and pass the `PaymentRequest` Object
|
320 | as a prop.
|
321 |
|
322 | ```jsx
|
323 | class PaymentRequestForm extends React.Component {
|
324 | constructor(props) {
|
325 | super(props);
|
326 |
|
327 | // For full documentation of the available paymentRequest options, see:
|
328 | // https://stripe.com/docs/stripe.js#the-payment-request-object
|
329 | const paymentRequest = props.stripe.paymentRequest({
|
330 | country: 'US',
|
331 | currency: 'usd',
|
332 | total: {
|
333 | label: 'Demo total',
|
334 | amount: 1000,
|
335 | },
|
336 | });
|
337 |
|
338 | paymentRequest.on('token', ({complete, token, ...data}) => {
|
339 | console.log('Received Stripe token: ', token);
|
340 | console.log('Received customer information: ', data);
|
341 | complete('success');
|
342 | });
|
343 |
|
344 | paymentRequest.canMakePayment().then((result) => {
|
345 | this.setState({canMakePayment: !!result});
|
346 | });
|
347 |
|
348 | this.state = {
|
349 | canMakePayment: false,
|
350 | paymentRequest,
|
351 | };
|
352 | }
|
353 |
|
354 | render() {
|
355 | return this.state.canMakePayment ? (
|
356 | <PaymentRequestButtonElement
|
357 | paymentRequest={this.state.paymentRequest}
|
358 | className="PaymentRequestButton"
|
359 | style={{
|
360 | // For more details on how to style the Payment Request Button, see:
|
361 | // https://stripe.com/docs/elements/payment-request-button#styling-the-element
|
362 | paymentRequestButton: {
|
363 | theme: 'light',
|
364 | height: '64px',
|
365 | },
|
366 | }}
|
367 | />
|
368 | ) : null;
|
369 | }
|
370 | }
|
371 | export default injectStripe(PaymentRequestForm);
|
372 | ```
|
373 |
|
374 | ## Advanced integrations
|
375 |
|
376 | The above [Getting started](#getting-started) section outlines the most common
|
377 | integration, which makes the following assumptions:
|
378 |
|
379 | - The Stripe.js script is loaded before your application's code.
|
380 | - Your code is only run in a browser environment.
|
381 | - You don't need fine-grained control over the Stripe instance that
|
382 | `react-stripe-elements` uses under the hood.
|
383 |
|
384 | When all of these assumptions are true, you can pass the `apiKey` prop to
|
385 | `<StripeProvider>` and let `react-stripe-elements` handle the rest.
|
386 |
|
387 | When one or more of these assumptions doesn't hold true for your integration,
|
388 | you have another option: pass a Stripe instance as the `stripe` prop to
|
389 | `<StripeProvider>` directly. The `stripe` prop can be either `null` or the
|
390 | result of using `Stripe(apiKey, options)` to construct a [Stripe instance].
|
391 |
|
392 | [stripe-function]: https://stripe.com/docs/stripe-js/reference#stripe-function
|
393 |
|
394 | We'll now cover a couple of use cases which break at least one of the
|
395 | assumptions listed above.
|
396 |
|
397 | ### Loading Stripe.js asynchronously
|
398 |
|
399 | Loading Stripe.js asynchronously can speed up your initial page load, especially
|
400 | if you don't show the payment form until the user interacts with your
|
401 | application in some way.
|
402 |
|
403 | ```html
|
404 | <html>
|
405 | <head>
|
406 | <!-- ... -->
|
407 |
|
408 | <!-- Note the 'id' and 'async' attributes: -->
|
409 | <!-- ┌────────────┐ ┌───┐ -->
|
410 | <script id="stripe-js" src="https://js.stripe.com/v3/" async></script>
|
411 |
|
412 | <!-- ... -->
|
413 | </head>
|
414 | <!-- ... -->
|
415 | </html>
|
416 | ```
|
417 |
|
418 | Initialize `this.state.stripe` to `null` in the `constructor`, then update it in
|
419 | `componentDidMount` when the script tag has loaded.
|
420 |
|
421 | ```jsx
|
422 | class App extends React.Component {
|
423 | constructor() {
|
424 | super();
|
425 | this.state = {stripe: null};
|
426 | }
|
427 | componentDidMount() {
|
428 | if (window.Stripe) {
|
429 | this.setState({stripe: window.Stripe('pk_test_12345')});
|
430 | } else {
|
431 | document.querySelector('#stripe-js').addEventListener('load', () => {
|
432 | // Create Stripe instance once Stripe.js loads
|
433 | this.setState({stripe: window.Stripe('pk_test_12345')});
|
434 | });
|
435 | }
|
436 | }
|
437 | render() {
|
438 | // this.state.stripe will either be null or a Stripe instance
|
439 | // depending on whether Stripe.js has loaded.
|
440 | return (
|
441 | <StripeProvider stripe={this.state.stripe}>
|
442 | <Elements>
|
443 | <InjectedCheckoutForm />
|
444 | </Elements>
|
445 | </StripeProvider>
|
446 | );
|
447 | }
|
448 | }
|
449 | ```
|
450 |
|
451 | When loading Stripe.js asynchronously, the `stripe` prop provided by
|
452 | `injectStripe` will initially be `null`, and will update to the Stripe instance
|
453 | once you pass it in to your `StripeProvider`. You can find a working demo of
|
454 | this strategy in [async.js](demo/async/async.js). If you run the demo locally,
|
455 | you can view it at <http://localhost:8080/async/>.
|
456 |
|
457 | For alternatives to calling `setState`in `componentDidMount`, consider using a
|
458 | `setTimeout()`, moving the `if/else` statement to the `constructor`, or
|
459 | dynamically injecting a script tag in `componentDidMount`. For more information,
|
460 | see [stripe/react-stripe-elements][issue-154].
|
461 |
|
462 | [issue-154]: https://github.com/stripe/react-stripe-elements/issues/154
|
463 |
|
464 | ### Server-side rendering (SSR)
|
465 |
|
466 | If you're using `react-stripe-elements` in a non-browser environment
|
467 | (`React.renderToString`, etc.), Stripe.js is not available. To use
|
468 | `react-stripe-elements` with SSR frameworks, use the following instructions.
|
469 |
|
470 | The general idea is similar to the async loading snippet from the previous
|
471 | section (initialize `this.state.stripe` to `null` in `constructor`, update in
|
472 | `componentDidMount`), but this time we don't have to wait for the script tag to
|
473 | load in `componentDidMount`; we can use `window.Stripe` directly.
|
474 |
|
475 | ```jsx
|
476 | class App extends React.Component {
|
477 | constructor() {
|
478 | super();
|
479 | this.state = {stripe: null};
|
480 | }
|
481 | componentDidMount() {
|
482 | // Create Stripe instance in componentDidMount
|
483 | // (componentDidMount only fires in browser/DOM environment)
|
484 | this.setState({stripe: window.Stripe('pk_test_12345')});
|
485 | }
|
486 | render() {
|
487 | return (
|
488 | <StripeProvider stripe={this.state.stripe}>
|
489 | <Elements>
|
490 | <InjectedCheckoutForm />
|
491 | </Elements>
|
492 | </StripeProvider>
|
493 | );
|
494 | }
|
495 | }
|
496 | ```
|
497 |
|
498 | Inside your form, `<InjectedCheckoutForm />`, `this.props.stripe` will either be
|
499 | `null` or a valid Stripe instance. This means that it will be `null` when
|
500 | rendered server-side, but set when rendered in a browser.
|
501 |
|
502 | ### Using an existing Stripe instance
|
503 |
|
504 | In some projects, part of the project uses React, while another part doesn't.
|
505 | For example, maybe you have business logic and view logic separate. Or maybe you
|
506 | use `react-stripe-elements` for your credit card form, but use Stripe.js APIs
|
507 | directly for tokenizing bank account information.
|
508 |
|
509 | You can use the `stripe` prop to get more fine-grained control over the Stripe
|
510 | instance that `<StripeProvider>` uses. For example, if you have a `stripe`
|
511 | instance in a Redux store that you pass to your `<App />` as a prop, you can
|
512 | pass that instance directly into `<StripeProvider>`:
|
513 |
|
514 | ```jsx
|
515 | class App extends React.Component {
|
516 | render() {
|
517 | return (
|
518 | <StripeProvider stripe={this.props.stripe}>
|
519 | <Elements>
|
520 | <InjectedCheckoutForm />
|
521 | </Elements>
|
522 | </StripeProvider>
|
523 | );
|
524 | }
|
525 | }
|
526 | ```
|
527 |
|
528 | As long as `<App />` is provided a non-`null` `stripe` prop, `this.props.stripe`
|
529 | will always be available within your `InjectedCheckoutForm`.
|
530 |
|
531 | ## Component reference
|
532 |
|
533 | ### `<StripeProvider>`
|
534 |
|
535 | All applications using `react-stripe-elements` must use the `<StripeProvider>`
|
536 | component, which sets up the Stripe context for a component tree.
|
537 | `react-stripe-elements` uses the provider pattern (which is also adopted by
|
538 | tools like [`react-redux`](https://github.com/reactjs/react-redux) and
|
539 | [`react-intl`](https://github.com/yahoo/react-intl)) to scope a Stripe context
|
540 | to a tree of components.
|
541 |
|
542 | This allows configuration like your API key to be provided at the root of a
|
543 | component tree. This context is then made available to the `<Elements>`
|
544 | component and individual `<*Element>` components that we provide.
|
545 |
|
546 | An integration usually wraps the `<StripeProvider>` around the application’s
|
547 | root component. This way, your entire application has the configured Stripe
|
548 | context.
|
549 |
|
550 | #### Props shape
|
551 |
|
552 | There are two _distinct_ props shapes you can pass to `<StripeProvider>`.
|
553 |
|
554 | ```jsx
|
555 | type StripeProviderProps =
|
556 | | {apiKey: string, ...}
|
557 | | {stripe: StripeObject | null};
|
558 | ```
|
559 |
|
560 | See [Advanced integrations](#advanced-integrations) for more information on when
|
561 | to use each.
|
562 |
|
563 | The `...` above represents that this component accepts props for any option that
|
564 | can be passed into `Stripe(apiKey, options)`. For example, if you are using
|
565 | [Stripe Connect](https://stripe.com/connect) and want to act on behalf of a
|
566 | connected account, you can pass `stripeAccount="acct_123"` as a property to
|
567 | `<StripeProvider>`. This will get used just like passing `stripeAccount` in the
|
568 | options of the `Stripe` constructor or like using `stripe_account` when your
|
569 | backend calls the Stripe API directly
|
570 |
|
571 | ### `<Elements>`
|
572 |
|
573 | The `Elements` component wraps groups of Elements that belong together. In most
|
574 | cases, you want to wrap this around your checkout form.
|
575 |
|
576 | #### Props shape
|
577 |
|
578 | This component accepts all `options` that can be passed into
|
579 | `stripe.elements(options)` as props.
|
580 |
|
581 | ```jsx
|
582 | type ElementsProps = {
|
583 | locale?: string,
|
584 | fonts?: Array<Object>,
|
585 | // The full specification for `elements()` options is here: https://stripe.com/docs/elements/reference#elements-options
|
586 | };
|
587 | ```
|
588 |
|
589 | ### `<*Element>` components
|
590 |
|
591 | These components display the UI for Elements, and must be used within
|
592 | `StripeProvider` and `Elements`.
|
593 |
|
594 | #### Available components
|
595 |
|
596 | (More to come!)
|
597 |
|
598 | - `CardElement`
|
599 | - `CardNumberElement`
|
600 | - `CardExpiryElement`
|
601 | - `CardCvcElement`
|
602 | - `PaymentRequestButtonElement`
|
603 | - `IbanElement`
|
604 | - `IdealBankElement`
|
605 |
|
606 | #### Props shape
|
607 |
|
608 | These components accept all `options` that can be passed into
|
609 | `elements.create(type, options)` as props.
|
610 |
|
611 | ```jsx
|
612 | type ElementProps = {
|
613 | id?: string,
|
614 | className?: string,
|
615 |
|
616 | // For full documentation on the events and payloads below, see:
|
617 | // https://stripe.com/docs/elements/reference#element-on
|
618 | onBlur?: () => void,
|
619 | onChange?: (changeObject: Object) => void,
|
620 | onFocus?: () => void,
|
621 | onReady?: (StripeElement) => void,
|
622 | };
|
623 | ```
|
624 |
|
625 | The props for the `PaymentRequestButtonElement` are:
|
626 |
|
627 | ```jsx
|
628 | type PaymentRequestButtonProps = {
|
629 | id?: string,
|
630 | className?: string,
|
631 |
|
632 | paymentRequest: StripePaymentRequest,
|
633 |
|
634 | onBlur?: () => void,
|
635 | onClick?: () => void,
|
636 | onFocus?: () => void,
|
637 | onReady?: (StripeElement) => void,
|
638 | };
|
639 | ```
|
640 |
|
641 | #### Using `onReady`
|
642 |
|
643 | Note that the `onReady` callback gives you access to the underlying [Element]
|
644 | created with Stripe.js. You can use this to get access to all the underlying
|
645 | methods that a Stripe Element supports.
|
646 |
|
647 | For example, you can use `onReady` to force your element to focus:
|
648 |
|
649 | ```jsx
|
650 | // CardSection.js
|
651 | import React from 'react';
|
652 | import {CardElement} from 'react-stripe-elements';
|
653 |
|
654 | class CardSection extends React.Component {
|
655 | render = () => {
|
656 | return (
|
657 | <label>
|
658 | Card details
|
659 | <CardElement onReady={(el) => el.focus()} />
|
660 | </label>
|
661 | );
|
662 | };
|
663 | }
|
664 |
|
665 | export default CardSection;
|
666 | ```
|
667 |
|
668 | (Note that this functionality is new as of react-stripe-elements v1.6.0.)
|
669 |
|
670 | [element]: https://stripe.com/docs/stripe-js/reference#other-methods
|
671 |
|
672 | ### `injectStripe` HOC
|
673 |
|
674 | ```jsx
|
675 | function injectStripe(
|
676 | WrappedComponent: ReactClass,
|
677 | options?: {
|
678 | withRef?: boolean = false,
|
679 | }
|
680 | ): ReactClass;
|
681 | ```
|
682 |
|
683 | Use `injectStripe` to wrap a component that needs to interact with `Stripe.js`
|
684 | to create sources or tokens.
|
685 |
|
686 | 1. First, create a component that accepts the `stripe` prop and calls one of
|
687 | the Stripe or Elements methods when necessary.
|
688 | 2. Wrap that component by passing it to `injectStripe` so that it actually
|
689 | receives the `stripe` and `elements` props.
|
690 | 3. Render the component that `injectStripe` returns.
|
691 |
|
692 | #### Example
|
693 |
|
694 | ```jsx
|
695 | // 1. Create a component that uses this.props.stripe:
|
696 | class CheckoutForm extends React.Component {
|
697 | render() {
|
698 | /* ... */
|
699 | }
|
700 | onCompleteCheckout() {
|
701 | this.props.stripe
|
702 | .createPaymentMethod({
|
703 | type: 'card',
|
704 | card: this.props.stripe.getElement('card'),
|
705 | })
|
706 | .then(/* ... */);
|
707 | }
|
708 | }
|
709 |
|
710 | // 2. Wrap it in a higher-order component that provides the `stripe` prop:
|
711 | const InjectedCheckoutForm = injectStripe(CheckoutForm);
|
712 |
|
713 | // 3. Render the wrapped component in your app:
|
714 | const CheckoutRoute = (props) => (
|
715 | <div>
|
716 | <InjectedCheckoutForm />
|
717 | </div>
|
718 | );
|
719 | ```
|
720 |
|
721 | `injectStripe` will work with any method of providing the actual Stripe instance
|
722 | with `StripeProvider`, whether you just give it an api key,
|
723 | [load Stripe.js asynchronously](#loading-stripejs-asynchronously), or
|
724 | [pass in an existing instance](#using-an-existing-stripe-instance).
|
725 |
|
726 | Within the context of `Elements`, `stripe.createToken` and `stripe.createSource`
|
727 | wrap methods of the same name in
|
728 | [Stripe.js](https://stripe.com/docs/stripe-js/reference#stripe-create-Token).
|
729 | Calls to them automatically infer and pass the `Element` object as the first
|
730 | argument.
|
731 |
|
732 | If the `withRef` option is set to `true`, the wrapped component instance will be
|
733 | available with the `getWrappedInstance()` method of the wrapper component. This
|
734 | feature can not be used if the wrapped component is a stateless function
|
735 | component.
|
736 |
|
737 | Within the wrapped component, the `stripe` and `elements` props have the type:
|
738 |
|
739 | ```jsx
|
740 | type FactoryProps = {
|
741 | elements: null | {
|
742 | getElement: (type: string) => Element | null,
|
743 | // For more detail and documentation on other methods available on
|
744 | // the `elements` object, please refer to our official documentation:
|
745 | // https://stripe.com/docs/elements/reference#the-elements-object
|
746 | },
|
747 | stripe: null | {
|
748 | createToken: (tokenData: {type?: string}) => Promise<{
|
749 | token?: Object,
|
750 | error?: Object,
|
751 | }>,
|
752 | createSource: (sourceData: {type: string}) => Promise<{
|
753 | source?: Object,
|
754 | error?: Object,
|
755 | }>,
|
756 | createPaymentMethod: (
|
757 | paymentMethodData: Object
|
758 | ) => Promise<{
|
759 | paymentMethod?: Object,
|
760 | error?: Object,
|
761 | }>,
|
762 | confirmCardPayment: (
|
763 | clientSecret: string,
|
764 | paymentIntentData?: Object
|
765 | ) => Promise<{
|
766 | paymentIntent?: Object,
|
767 | error?: Object,
|
768 | }>,
|
769 | confirmCardSetup: (
|
770 | clientSecret: string,
|
771 | paymentIntentData?: Object
|
772 | ) => Promise<{
|
773 | setupIntent?: Object,
|
774 | error?: Object,
|
775 | }>,
|
776 | // For more detail and documentation on other methods available on
|
777 | // the `stripe` object, please refer to our official documentation:
|
778 | // https://stripe.com/docs/elements/reference#the-stripe-object
|
779 | },
|
780 | };
|
781 | ```
|
782 |
|
783 | The `stripe` and `elements` props can only be `null` if you are using one of the
|
784 | [Advanced integrations](#advanced-integrations) mentioned above, like loading
|
785 | Stripe.js asynchronously or providing an existing instance. If you are using a
|
786 | basic integration where you pass in an api key to `<StripeProvider/>`, they will
|
787 | always be present.
|
788 |
|
789 | ## Troubleshooting
|
790 |
|
791 | `react-stripe-elements` may not work properly when used with components that
|
792 | implement `shouldComponentUpdate`. `react-stripe-elements` relies heavily on
|
793 | React's `context` feature and `shouldComponentUpdate` does not provide a way to
|
794 | take context updates into account when deciding whether to allow a re-render.
|
795 | These components can block context updates from reaching `react-stripe-element`
|
796 | components in the tree.
|
797 |
|
798 | For example, when using `react-stripe-elements` together with
|
799 | [`react-redux`](https://github.com/reactjs/react-redux) doing the following will
|
800 | not work:
|
801 |
|
802 | ```jsx
|
803 | const Component = connect()(injectStripe(_Component));
|
804 | ```
|
805 |
|
806 | In this case, the context updates originating from the `StripeProvider` are not
|
807 | reaching the components wrapped inside the `connect` function. Therefore,
|
808 | `react-stripe-elements` components deeper in the tree break. The reason is that
|
809 | the `connect` function of `react-redux`
|
810 | [implements `shouldComponentUpdate`](https://github.com/reactjs/react-redux/blob/master/docs/troubleshooting.md#my-views-arent-updating-when-something-changes-outside-of-redux)
|
811 | and blocks re-renders that are triggered by context changes outside of the
|
812 | connected component.
|
813 |
|
814 | There are two ways to prevent this issue:
|
815 |
|
816 | 1. Change the order of the functions to have `injectStripe` be the outermost
|
817 | one:
|
818 |
|
819 | ```jsx
|
820 | const Component = injectStripe(connect()(_CardForm));
|
821 | ```
|
822 |
|
823 | This works, because `injectStripe` does not implement `shouldComponentUpdate`
|
824 | itself, so context updates originating from the `redux` `Provider` will still
|
825 | reach all components.
|
826 |
|
827 | 2. You can use the [`pure: false`][pure-false] option for redux-connect:
|
828 |
|
829 | ```jsx
|
830 | const Component = connect(
|
831 | mapStateToProps,
|
832 | mapDispatchToProps,
|
833 | mergeProps,
|
834 | {
|
835 | pure: false,
|
836 | }
|
837 | )(injectStripe(_CardForm));
|
838 | ```
|
839 |
|
840 | [pure-false]:
|
841 | https://github.com/reactjs/react-redux/blob/master/docs/api.md#connectmapstatetoprops-mapdispatchtoprops-mergeprops-options
|
842 |
|
843 | ## Development
|
844 |
|
845 | Install dependencies:
|
846 |
|
847 | yarn install
|
848 |
|
849 | Run the demo:
|
850 |
|
851 | yarn run demo
|
852 |
|
853 | Run the tests:
|
854 |
|
855 | yarn run test
|
856 |
|
857 | Build:
|
858 |
|
859 | yarn run build
|
860 |
|
861 | We use [prettier](https://github.com/prettier/prettier) for code formatting:
|
862 |
|
863 | yarn run prettier
|
864 |
|
865 | To update the ToC in the README if any of the headers changed:
|
866 |
|
867 | yarn run doctoc
|
868 |
|
869 | Checks:
|
870 |
|
871 | yarn test
|
872 | yarn run lint
|
873 | yarn run flow
|