In this guide, we’ll use Swell-js to render Stripe Elements with React. Our objective is to lay the groundwork for a checkout that you can build upon to include additional custom logic you may wish to implement within your checkout flow.

  • A new or existing React project
  • Stripe connected as the payment gateway in your Swell store's Payment settings.

To get started, install Swell-js with the following command:

Install swell-js
npm install --save swell-js

With this installed, we can move on to the card components.

To create a card component, create a card.js component in src:

Create a card component
export default class Card extends Component {
  render() {
      return(
          <div>Card</div>
      );
  }
}

Once created, we can render our new card component in index.js:

Rendering the card component
import React, { Component } from 'react';
import { render } from 'react-dom';
import swell from 'swell-js';
import Card from './Card';
import './style.css';

class App extends Component {
  constructor() {
    super();
    swell.init('<store_id>', '<public_key>');
  }

  render() {
    return (
      <div>
        <Card swell={swell} />
      </div>
    );
  }
}

render(<App />, document.getElementById('root'));

In order to render Stripe Elements and tokenize cards using Swell.js, we’ll need to have a cart initialized and a product already in the cart. Swell.js handles the creation of Stripe paymentIntents automatically in the swell.payment.tokenize() method.

With the above in mind, let’s create a method to initialize a cart and add a product on initialization. In this case, you can imagine this as a direct “1-click” checkout.

Initialize a cart
async createCart(){
  await swell.cart.setItems([]); //Used to reset the cart on init
  await swell.cart.addItem({
    product_id: '<product_id>',
  });
};

Now we can call our createCart() in the componentDidMount() method and add the following logic to render the Card element:

Card element rendering logic
async componentDidMount() {
  await this.createCart();

  this.props.swell.payment.createElements({
    card: {
      elementId: '#card-element', // Default: #card-element
      options: {
        // Options are passed as a direct argument to stripe.js
         hidePostalCode: true,
      },
      onChange: (event) => {
        // Optional, called when the Element value changes
      },
      onReady: (event) => {
        // Optional, called when the Element is fully rendered
        console.log('ready');
      },
      onFocus: (event) => {
        // Optional, called when the Element gains focus
      },
      onBlur: (event) => {
        // Optional, called when the Element loses focus
      },
      onEscape: (event) => {
        // Optional, called when the escape key is pressed within an Element
      },
      onClick: (event) => {
        // Optional, called when the Element is clicked
        console.log('click');
      },
      onSuccess: (result) => {
        // Optional, called on card payment success
        console.log('success');
        this.setState({ tokenized: true });
      },
      onError: (error) => {
        // Optional, called on card payment error
        (err) => onError(err.message);
      },
    },
  });
}

In order to render the Card element, we now have to edit our render() method:

Edit the render() method
render() {
  return (
    <div class="container">
      <div id="card-element"/> //Must match the elementId in swell.payment.createElements
    </div>
  );
}

Now that the rendering logic is in place, run npm start—you should be able to see your card element render.

Now we’ll have to add our tokenize method—this takes in the card details we’re passing into the Card element which creates the paymentIntent and paymentMethod in Stripe.

Tokenize method
tokenize = () => {
  this.props.swell.payment.tokenize({
    card: {
      onSuccess: () => {
        console.log('tokenize success');
      },
      onError: (err) => {
        console.log(err);
      },
    },
  });
}

Next, create a button to call our tokenize() method. For this example, we’re separating out the tokenizing logic from the submit; however, you can also merge this logic into your submit function.

Using a button to call the tokenize() method
render() {
  return (
    <div class="container">
      <div id="card-element"/> //Must match the elementId in swell.payment.createElements
      <button onClick={this.tokenize}>Tokenize</button> //Add
    </div>
  );
}

Fill in a Stripe test card, and use Stripe's guide for testing cards for various scenarios while building your checkout. For a successful response, we can use 4242 4242 4242 4242 along with any future expiration date and CVC. The swell.payment.tokenize() method will attach the paymentIntent to the cart.

Once a card has been successfully tokenized, you can then submit the order. Create a submit() method to also update the cart with an email, as this is required to submit an order.

The submit() method
submit = async () => {
  await this.props.swell.cart.update({
    account: {
      email: '<email>', //An email is required to submit an order
    },
  });
  const order = await this.props.swell.cart.submitOrder();
  console.log(order);
}

And we can now create a new button to call our submit() method:

Using a button to call the submit() method
render() {
  return (
    <div class="container">
      <div id="card-element"/> //Must match the elementId in swell.payment.createElements
      <button onClick={this.tokenize}>Tokenize</button>
      <button onClick={this.submit}>Submit</button> //Add
    </div>
  );
}

Clicking our submit button should now submit the order, and you should see a new order appear in your Swell store. Congrats! You’re now on your way to creating your own custom checkout. From here, you can continue building out your checkout flow, adding extra steps like shipping and billing info where necessary.