Improving on other answers, I got the following solution. Take it with a grain of salt, though. The CSS for .StripeElement--focus
and .card-element-disabled
is copied from Bootstrap, so you might want to take them from the version you're using (I have 4.4, I think).
Also, I did not copy the payment logic, because it's specific to my application, but I call disable_form
when the button is pressed and JavaScript begins processing stuff, and enable_form
when JavaScript is done and the form can be re-enabled (probably because there was an error, otherwise you just go to another page).
<style> .StripeElement--focus { color: #495057; background-color: #fff; border-color: #80bdff; outline: 0; box-shadow: 0 0 0 .2rem rgba(0,123,255,.25); } .card-element-disabled { background-color: #e9ecef; opacity: 1; } #card-element { display: flex; align-items: center; } #card-element div { flex-grow: 1; } #card-element-error { color: #ff0000; }</style><script> function disable_form() { $(".form-control").prop('disabled', true); card.update({disabled: true}); $("#submit-btn").prop('disabled', true).html("Loading"); $("#card-element").addClass('card-element-disabled'); } function enable_form() { $(".form-control").prop('disabled', false); card.update({disabled: false}); $("#submit-btn").prop('disabled', false).html("Submit"); $("#card-element").removeClass('card-element-disabled'); } var stripe = Stripe('{{ stripe_publishable_key }}'); var elements = stripe.elements(); var card = elements.create('card'); function setup_stripe() { card.mount('#card-element'); } setTimeout(setup_stripe, 0);</script><form id="payment-form"><!-- all other fields --><div class="form-group"><label for="card-element">Card number</label><div id="card-element" class="form-control"></div></div><div id="card-element-error" role="alert"></div><button type="submit" class="btn btn-primary" id="submit-btn">Submit</button></form>