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?
The element is an iframe, which is another window, which has its own window object and document object.
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 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.
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.
<!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.
<!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.
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');
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With