Custom Stripe Forms With No Server Code

Stripe Elements enable custom payment forms, using your own HTML, CSS and Javascript, but require a server. That's where Formspree comes in.

Stripe Elements are intended for building custom payment experiences. However, they require a server to submit the charge to Stripe. What if you’re a front end designer or developer that doesn’t want to build or maintain your own server? Or what if you’re working on a static site that doesn’t have a server? Well, this tutorial is for you!

In this tutorial we’ll create a payment form using Stripe Elements that submits to Formspree. Then we’ll configure Formspree to accept the payment and complete the Stripe transaction. In the end we’ll have a custom payment form that fits our website’s unique style. Formspree will be handling the charges and delivering receipts. We’ll even be able to send those receipts to a Slack channel or Trello board.

Let’s get started!

Step 1: Build a Custom Form with Stripe Elements

We’ll start by building a form to collect card details using Stripe Elements and some CSS styles to match our site. Stripe already has great documentation that describes how to collect card information. You can find it here.

We’ll be creating a form that collects the name, email and card number of our customer. However, rather than building our own backend to accept the payment token and create the Stripe charge, we’ll configure it to submit to Formspree.

Here’s what our form looks like:

First let’s create the HTML form using standard inputs for Name and Email, and a Stripe Elements card field:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
<form action="http://formspree.io/YOUR_FORM_ID" 
  method="post" id="payment-form"
>
  <label for="name">Name</label>
  <input type="text" name="name" required/>

  <label for="email">Email</label>
  <input type="email" name="email" required/>

  <label for="card-element">Credit or debit card</label>
  <div id="card-element">
    <!-- A Stripe Element will be inserted here. -->
  </div>

  <!-- Used to display form errors. -->
  <div id="card-errors" role="alert"></div>

  <input type="submit" value="Submit Payment"/>
</form>

This form will submit name and email data to Formspree along with the card details that we get from Stripe. In order for it to work correctly, we need to replace YOUR_FORM_ID on line 1 above with an ID we’ll create in Step 2.

Next we’ll add the Javascript necessary to create the Card element, and retrieve a token from Stripe before submitting the form. This is nearly identical to the example javascript in the Stripe docs, with one important difference we’ll discuss below.

 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
<script src="https://js.stripe.com/v3/"></script>
<script>
  var stripe = Stripe('YOUR_STRIPE_PUBLIC_KEY');
  var elements = stripe.elements();

  // Create an instance of the card Element.
  var card = elements.create('card');

  // Add an instance of the card Element into the `card-element` <div>.
  card.mount('#card-element');

  // Handle real-time validation errors from the card Element.
  card.addEventListener('change', function(event) {
    var displayError = document.getElementById('card-errors');
    if (event.error) {
      displayError.textContent = event.error.message;
    } else {
      displayError.textContent = '';
    }
  });

  // Handle form submission.
  var form = document.getElementById('payment-form');
  form.addEventListener('submit', function(event) {
    event.preventDefault();
    stripe.createToken(card).then(function(result) {
      if (result.error) {
        // Inform the user if there was an error.
        var errorElement = document.getElementById('card-errors');
        errorElement.textContent = result.error.message;
      } else {
        // Send the token to your server.
        stripeTokenHandler(result.token);
      }
    });
  });

  // Submit the form with the token ID.
  function stripeTokenHandler(token) {
    // Insert the token ID into the form so it gets submitted to the server
    var form = document.getElementById('payment-form');
    var hiddenInput = document.createElement('input');
    hiddenInput.setAttribute('type', 'hidden');
    hiddenInput.setAttribute('name', '_stripe_token');  // <-- important
    hiddenInput.setAttribute('value', token.id);
    form.appendChild(hiddenInput);
    // Submit the form
    form.submit();
  }    
</script>

The most important change is on line 44: We need to set the name of the field that contains the stripe token to _stripe_token. This is a special field name that Formspree understands and expects when the Stripe plugin is enabled.

Finally we need to style our form to match our website. This is an exercise left to the reader. The example above uses a form reset.css that works great for most websites. It inherits the site’s fonts and colors, and adds consistent spacing and borders for inputs. And, of course, it works with Stripe Elements. You can grab it here.

We’re almost ready to rock! We just need to connect to Formspree, which will complete the charge using a price and description we’ll configure in Step 2.

Step 2: Creating a Form Endpoint in Formspree

Now let’s head over to https://formspree.io/create and enter the email address where we’ll receive form submissions.

We’ll need to create a Formspree account if we haven’t already. Once the form is created, we’ll be redirected to an integration tab that shows our form URL. It’ll look like this:

Note the form endpoint. This is the value we need to substitute into our form from Step 1. Find this line and replace YOUR_FORM_ID using the ID provided above:

  <form action="http://formspree.io/YOUR_FORM_ID" method="post" id="payment-form">

Now we’ll connect our form to Stripe by adding a Plugin. Let’s go to the Plugins tab and then click the Stripe button.

This will prompt us to login to Stripe or create a new account. Once connected, we’ll need to provide a short description and the price, or amount, of each charge.

Now that we have a Formspree form endpoint that’s connected to Stripe, we’re ready to test our form!

Step 3: Submit the form

We can now start collecting payments with our form. It’s not necessary to build a server to create the charge. The plugin we configured in Step 2 will handle it.

Let’s submit the form and see what happens!

Note: Our form uses the standard HTML submit action and redirects to the default Formspree thanks screen. We can also redirect to a custom “Thank You” page by adding a _next field. (See the Formspree docs) Finally we can use Ajax and React to submit the form. (See our series on Three Ways to Build React Forms)

After submitting, we can see the latest submission contains a link to the Stripe receipt.

If we view the payment in Stripe, we can see that the additional fields from our form (the name and email) are also reflected in the charge’s metadata.

That’s a wrap! We’ll follow up soon with additional guides for how to build custom Stripe forms with React, and more advanced payment flows. If you have any suggestions or feedback hit us up below!


Got Feedback?