56 votes

Comment puis-je styliser une entrée Stripe Elements avec Bootstrap ?

Je suis en train de créer un site web simple qui traitera les paiements avec Stripe. J'utilise Bootstrap pour le style. Lorsque j'utilise Stripe Elements pour insérer les champs de paiement, ils ne sont pas stylisés avec Bootstrap. Comment puis-je appliquer le style de Bootstrap aux champs de paiement d'Elements ?

53voto

Brian Gottier Points 26

J'ai dû résoudre ce problème, car j'utilisais Stripe.js v2, et le support technique de Stripe m'a expliqué la faille de sécurité. Je me suis donc senti obligé de passer à Stripe.js v3 "Elements". Ce qu'ils ont dit, c'est que tout javascript sur la même page que les éléments de votre formulaire de carte de crédit pouvait obtenir les valeurs des données sensibles de la carte de crédit. Je suppose que cela pourrait se produire si une personne tirait des scripts externes ... et je suppose que cela a dû se produire, sinon ils ne s'en seraient pas souciés. Quoi qu'il en soit, voici comment j'ai fait fonctionner mes éléments Stripe.js v3 avec les groupes d'entrée de Bootstrap 4. C'est un exemple complet qui fonctionne, vous devez juste changer la clé publique.

Exemple par défaut basé sur jQuery

<!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>

J'ai testé uniquement dans Firefox, Chrome, et Chrome sur Android. Il semble que cela fonctionne bien. Faites-moi savoir si vous rencontrez des problèmes.

Exemple facultatif basé sur Vue.js

<!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/vue@2.5.13/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>

Cet exemple de Vue.js pourrait bénéficier d'un peu de travail, mais il peut vous aider à démarrer.

0 votes

Ça m'a l'air génial ! Y

0 votes

Cela a bien fonctionné, mais comment changer le style en cas d'erreur ?

0 votes

Voici un simple Codelply que j'ai créé à partir de cela. codeply.com/p/PPX9p3vKEL

48voto

michael Points 551

Après avoir creusé un peu plus dans la documentation, j'ai découvert que https://stripe.com/docs/stripe.js#the-element-container dit "Vous devez donner du style au conteneur sur lequel vous montez un élément comme s'il s'agissait d'un élément sur votre page".

En ajoutant la fonction de Bootstrap form-control à la classe <div> Je monte l'élément dans, le champ ressemble presque à n'importe quel autre champ de saisie de style Bootstrap :

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

Pour une raison quelconque, la hauteur du champ ne correspond pas tout à fait, mais en tâtonnant, j'y suis arrivé. avec :

var stripe = Stripe('your_key');
var elements = stripe.elements();
var card = elements.create('card', { style:
  {
    base: {
      lineHeight: '1.429'
    }
  }
});
card.mount('#card-element');

2 votes

C'est vrai, mais vous devez également appliquer une couleur de bordure lorsque l'élément est focalisé. De plus, si vous utilisez Bootstrap 4 beta et que vous essayez d'utiliser des groupes d'entrée, vous devez modifier le CSS de votre élément de manière à ce qu'il soit display:block au lieu de display:flex . J'en ai fait une démonstration fonctionnelle... mais ce n'est pas vraiment la réponse à votre question... à moins que ce ne le soit.

0 votes

De bons points ! Cela semble être la réponse :) J'aimerais bien voir la démo.

0 votes

Dans mon cas, form-control est enlevé d'une manière ou d'une autre.

26voto

Abram Points 3501

C'est tout ce qu'il nous fallait pour utiliser

  <div class="form-group">
    <label for="card-element">Credit or debit card</label>
    <div id="card-element" class="form-control" style='height: 2.4em; padding-top: .7em;'>
      <!-- A Stripe Element will be inserted here. -->
    </div>
  </div>

enter image description here

0 votes

C'est très simple.

6 votes

À quoi ressemble le javascript ?

0 votes

Vous ne pouvez styliser que certaines zones spécifiques par le biais de css en ligne et le reste doit être fait par JS.

8voto

Louie Bacaj Points 189

J'ajoute une autre réponse car j'ai eu l'impression que la plus simple d'entre elles était légèrement incomplète. J'ai ajouté l'affichage de l'erreur et le JavaScript utilisé pour envoyer le jeton au back-end au cas où vous voudriez le faire.

Ce HTML (qui provient directement de leur documentation par défaut avec des éléments Bootstrap 4 ajoutés)

<form action="/charge" method="post" id="payment-form">
  <div class="form-group">
    <label for="card-element">
        Credit or debit card
    </label>
    <div id="card-element" class="form-control">
        <!-- A Stripe Element will be inserted here. -->
    </div>

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

  <button>Submit Payment</button>
</form>

Et voici le JavaScript (encore une fois tiré de leur documentation par défaut mais j'utilise jQuery ici mais vous n'êtes pas obligé)

<script src="https://js.stripe.com/v3/"></script>
<script>
(function ($) {
    // Set your publishable key: remember to change this to your live publishable key in production
    // See your keys here: https://dashboard.stripe.com/account/apikeys
    var stripe = Stripe('yourPublishableKeyHere');
    var elements = stripe.elements();

    // Custom styling can be passed to options when creating an Element.
    var style = {
      base: {
        // Add your base input styles here. For example:
        fontSize: '16px',
        color: '#32325d',
      },
    };

    // Create an instance of the card Element.
    var card = elements.create('card', {style: style});

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

    // Create a token or display an error when the form is submitted.
    var form = document.getElementById('payment-form');
    form.addEventListener('submit', function(event) {
      event.preventDefault();

      stripe.createToken(card).then(function(result) {
        if (result.error) {
          // Inform the customer that 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);
        }
      });
    });

    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', 'stripeToken');
      hiddenInput.setAttribute('value', token.id);
      form.appendChild(hiddenInput);

      // Submit the form
      form.submit();
    }
})(jQuery);
</script>

1voto

En améliorant les autres réponses, j'ai obtenu la solution suivante. Prenez-la avec un grain de sel, cependant. Le CSS pour .StripeElement--focus y .card-element-disabled est copié de Bootstrap, donc vous pouvez les prendre de la version que vous utilisez (j'ai 4.4, je pense).

De plus, je n'ai pas copié la logique de paiement, car elle est spécifique à mon application, mais j'appelle disable_form lorsque le bouton est pressé et que JavaScript commence à traiter les données, et enable_form lorsque JavaScript est terminé et que le formulaire peut être réactivé (probablement parce qu'il y a eu une erreur, sinon vous allez simplement sur une autre 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>

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X