Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I style a Stripe Elements input with Bootstrap?

I'm building a simple website that will process payments with Stripe. I'm using Bootstrap for my styling. When I use Stripe Elements to insert the payment fields, they aren't styled with Bootstrap. How can I apply Bootstrap's styling to the Elements payment fields?

like image 232
michael Avatar asked Sep 04 '17 14:09

michael


People also ask

Is stripe elements an iframe?

The element is an iframe, which is another window, which has its own window object and document object.

Does stripe have a design system?

This includes working on Sail, the design system and component library that all of Stripe's products are built on. As a product designer on the team, you'll work at the intersection of design and engineering, driving both decisions that directly impact the design and code quality of Stripe products.

What is stripe JavaScript?

What is Stripe JS? Well, Stripe. js is a JavaScript library which you can wire into your checkout form to handle the credit card information. When a user signs up using the checkout form, it sends the credit card information directly from the user's browser to Stripe's servers.


2 Answers

Alright, so I had to figure this out, because I was using Stripe.js v2, and the security vulnerability was explained to me by Stripe tech support, so I felt obligated to switch to Stripe.js v3 "Elements". What they said was that any javascript on the same page as your credit card form elements could obtain the values of the sensitive credit card data. I suppose this could happen if a person was pulling in external scripts ... and I suppose it must have happened, or they wouldn't care about it. Anyway, this is how I got my Stripe.js v3 elements working with Bootstrap 4 input groups. It's a full working example, you'd just need to change out the public key.

Default jQuery Based Example

<!DOCTYPE html> <html lang="en"> <head>     <meta charset="utf-8">     <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">     <title>Stripe.js v3 with Bootstrap 4 Test</title>     <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">     <style>         /* Blue outline on focus */         .StripeElement--focus {             border-color: #80BDFF;             outline:0;             box-shadow: 0 0 0 .2rem rgba(0,123,255,.25);             transition: border-color .15s ease-in-out, box-shadow .15s ease-in-out;         }         /* Can't see what I type without this */         #card-number.form-control,         #card-cvc.form-control,         #card-exp.form-control {             display:inline-block;         }     </style> </head> <body>      <div class="container-fluid">         <h1 class="mt-5">Stripe.js v3 with Bootstrap 4 (beta) Test</h1>         <div id="card-errors" role="alert"></div>         <div class="card">             <div class="card-body">                 <form id="payment-form">                     <label for="name">Name on Card</label>                     <div class="input-group mb-2">                         <div class="input-group-prepend">                             <span class="input-group-text">A</span>                         </div>                         <input type="text" class="form-control" id="name">                         <div class="input-group-append">                             <span class="input-group-text">B</span>                         </div>                     </div>                     <label for="card-number">Credit Card Number</label>                     <div class="input-group mb-2">                         <div class="input-group-prepend">                             <span class="input-group-text">C</span>                         </div>                         <span id="card-number" class="form-control">                             <!-- Stripe Card Element -->                         </span>                         <div class="input-group-append">                             <span class="input-group-text">D</span>                         </div>                     </div>                     <label for="card-cvc">CVC Number</label>                     <div class="input-group mb-2">                         <div class="input-group-prepend">                             <span class="input-group-text">E</span>                         </div>                         <span id="card-cvc" class="form-control">                             <!-- Stripe CVC Element -->                         </span>                     </div>                     <label for="card-exp">Expiration</label>                     <div class="input-group mb-2">                         <span id="card-exp" class="form-control">                             <!-- Stripe Card Expiry Element -->                         </span>                         <div class="input-group-append">                             <span class="input-group-text">F</span>                         </div>                     </div>                     <button id="payment-submit" class="btn btn-primary mt-1">Submit Payment</button>                 </form>             </div>         </div>     </div>  <script src="https://code.jquery.com/jquery-3.2.1.min.js" integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4=" crossorigin="anonymous"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script> <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script> <script src="https://js.stripe.com/v3/"></script> <script>     $(document).ready(function(){          // Create a Stripe client         var stripe = Stripe('pk_test_XxXxXxXxXxXxXxXxXxXxXxXx');          // Create an instance of Elements         var elements = stripe.elements();          // Try to match bootstrap 4 styling         var style = {             base: {                 'lineHeight': '1.35',                 'fontSize': '1.11rem',                 'color': '#495057',                 'fontFamily': 'apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif'             }         };          // Card number         var card = elements.create('cardNumber', {             'placeholder': '',             'style': style         });         card.mount('#card-number');          // CVC         var cvc = elements.create('cardCvc', {             'placeholder': '',             'style': style         });         cvc.mount('#card-cvc');          // Card expiry         var exp = elements.create('cardExpiry', {             'placeholder': '',             'style': style         });         exp.mount('#card-exp');          // Submit         $('#payment-submit').on('click', function(e){             e.preventDefault();             var cardData = {                 'name': $('#name').val()             };             stripe.createToken(card, cardData).then(function(result) {                 console.log(result);                 if(result.error && result.error.message){                     alert(result.error.message);                 }else{                     alert(result.token.id);                 }             });         });      }); </script> </body> </html> 

I tested only in Firefox, Chrome, and Chrome on Android. Seems to work fine. Let me know if you experience any issues.

Optional Vue.js Based Example

<!DOCTYPE html> <html lang="en"> <head>     <meta charset="utf-8">     <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">     <title>Stripe.js v3 with Bootstrap 4 and Vue.js</title>     <link type="text/css" rel="stylesheet" href="https://unpkg.com/bootstrap/dist/css/bootstrap.min.css"/>     <link type="text/css" rel="stylesheet" href="https://unpkg.com/bootstrap-vue@latest/dist/bootstrap-vue.css"/>     <style>         /* This background color not essential for the example */         html, body {             background:#999;         }          /* Padding for Stripe Element containers */         .stripe-element-container {             padding-top: .55rem;             padding-bottom: .50rem;         }          /* Blue outline on focus */         .StripeElement--focus {             border-color: #80BDFF;             outline:0;             box-shadow: 0 0 0 .2rem rgba(0,123,255,.25);             transition: border-color .15s ease-in-out, box-shadow .15s ease-in-out;         }          /* Can't see what I type without this */         #card-number.form-control,         #card-cvc.form-control,         #card-exp.form-control {             display:inline-block;         }     </style> </head> <body>     <div id="app">         <stripe-form inline-template>             <div class="container-fluid">                 <div class="row">                     <div class="col-md-4 offset-md-4 pt-5">                         <div class="card">                             <div class="card-header">                                 <h3 class="mb-0">Pay Now</h3>                             </div>                             <div class="card-body">                                 <div v-bind:class="{alert: activeError, 'alert-danger': activeError}" role="alert" v-html="errorText"></div>                                  <form>                                      <div class="form-group mb-4">                                         <label for="name">Name on Card</label>                                         <input type="text" class="form-control" v-model="ccName" />                                     </div>                                      <div class="form-group">                                         <label for="card-number">Credit Card Number</label>                                         <span id="card-number" class="form-control stripe-element-container">                                             <!-- Stripe Card Element -->                                         </span>                                     </div>                                      <div class="form-group">                                         <label for="card-cvc">CVC Number</label>                                         <span id="card-cvc" class="form-control stripe-element-container">                                             <!-- Stripe CVC Element -->                                         </span>                                     </div>                                      <div class="form-group">                                         <label for="card-exp">Expiration</label>                                         <span id="card-exp" class="form-control stripe-element-container">                                             <!-- Stripe Card Expiry Element -->                                         </span>                                     </div>                                      <button @click.prevent="paymentSubmit" class="btn btn-primary mt-1 float-right">Submit Payment</button>                                  </form>                             </div>                         </div>                     </div>                 </div>             </div>         </stripe-form>         <modal></modal>     </div>  <script src="https://unpkg.com/[email protected]/dist/vue.js"></script> <script src="https://unpkg.com/babel-polyfill@latest/dist/polyfill.min.js"></script> <script src="https://unpkg.com/bootstrap-vue@latest/dist/bootstrap-vue.js"></script> <script src="https://js.stripe.com/v3/"></script> <script>  // Your Stripe public key const stripePublicKey = 'pk_test_XxXxXxXxXxXxXxXxXxXxXxXx';  /**  * Class allows firing of events and   * listening of events between components  */ window.Events = new class {      constructor(){         this.vue = new Vue();     }      fire( event, data = null ){         this.vue.$emit( event, data );     }      listenFor( event, callback ){         this.vue.$on( event, callback );     } }  /**  * See: https://bootstrap-vue.js.org/docs/components/modal/  */ Vue.component('modal', {      template: `         <div>             <b-modal ref="myModalRef" ok-only ok-title="Close" v-bind:title="title">                 <p class="mb-0">{{ body }}</p>             </b-modal>         </div>     `,      data: function(){         return {             title: '',             body: ''         }     },      methods: {         showModal () {           this.$refs.myModalRef.show()         }         /* This not needed for this example         ,         hideModal () {           this.$refs.myModalRef.hide()         }         */     },      created(){         Events.listenFor('modalShow', ( data ) => {             this.title = data.title;             this.body = data.message;             this.showModal();         });     }  });  Vue.component('stripe-form', {      data: function(){         return {              activeError: false,             errorText: '',             ccName: '',             stripe: null,             card: null,             cvc: null,             exp: null         }     },      methods: {         paymentSubmit: function(){             let cardData = {                 'name': this.ccName             };             // Ensure the name field is not empty             if( cardData.name.trim() == '' ){                 // Show an error                 this.activeError = true;                 this.errorText = '<b>Submission Error:</b><br />Name is required.';                 // Abort !!                 return;             }             this.stripe.createToken( this.card, cardData).then( (result) => {                 if(result.error && result.error.message){                      // Show any errors                     this.activeError = true;                     this.errorText = '<b>Submission Error:</b><br />' + result.error.message;                  }else{                      /**                      * Success message in modal.                      * This is normally where you'd post to your server,                       * and have it actually attempt the credit card transaction                      * using the token ID that was just received.                      */                     Events.fire('modalShow', {                         'title': 'Success',                         'message': result.token.id                     });                      // Clear the form                     this.activeError = false;                     this.errorText = '';                     this.ccName = '';                     // Stripe elements must be cleared in a special way                     this.card.clear();                     this.cvc.clear();                     this.exp.clear();                 }             });         }     },      mounted: function(){         // Create a Stripe client         this.stripe = Stripe( stripePublicKey );          // Create an instance of Elements         const elements = this.stripe.elements();          /**          * Try to match bootstrap 4 styling.          * --------------------------------          * fontSize was in rem units, but Stripe says that it should be in pixels.          */         const style = {             base: {                 'fontSize': '16px',                 'color': '#495057',                 'fontFamily': 'apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif'             }         };          // Card number         this.card = elements.create('cardNumber', {             'placeholder': '',             'style': style         });         this.card.mount('#card-number');          // CVC         this.cvc = elements.create('cardCvc', {             'placeholder': '',             'style': style         });         this.cvc.mount('#card-cvc');          // Card expiry         this.exp = elements.create('cardExpiry', {             'placeholder': '',             'style': style         });         this.exp.mount('#card-exp');     }  });  new Vue({ el: '#app' });  </script> </body> </html> 

This Vue.js example could benefit from some work, but may help get you started.

like image 122
Brian Gottier Avatar answered Sep 26 '22 21:09

Brian Gottier


After digging around the docs a bit more, I found that https://stripe.com/docs/stripe.js#the-element-container says "You should style the container you mount an Element to as if it were an on your page."

By adding Bootstrap's form-control class to the <div> I'm mounting the Element in, the field looks almost like any other Bootstrap-styled input field:

<div id="card-element" class="form-control"></div> 

For some reason, the height of the field doesn't quite match, but through trial and error, I got it with:

var stripe = Stripe('your_key'); var elements = stripe.elements(); var card = elements.create('card', { style:   {     base: {       lineHeight: '1.429'     }   } }); card.mount('#card-element'); 
like image 23
michael Avatar answered Sep 25 '22 21:09

michael