Using the Braintree V3 Drop-in UI

The Braintree V3 Drop-in UI allows more customization over how the Braintree payment method appears in the payment method step in Commerce versus the included V2 drop-in UI. See Braintree’s documentation for more details:

To use the new V3 Drop-In API, replace your Commerce theme’s frontend/gateways/braintree/form.twig template.

<div class="c-braintree-gateway">

    <span class="c-braintree-payment-errors"></span>
    <!-- Must be empty to correctly load Braintree -->
    <div id="c-braintree-payment-form-{{ method }}"></div>

<!-- Retreived nonce -->
<input id="braintree{{ method }}-nonce" type="hidden">

<script type="text/javascript">
    var braintree{{ method }}Loaded = false,
        teardownBraintree{{ method }} = false,
        braintree{{ method }} = null,
        braintree{{ method }}Form = document.querySelector("#c-choose-payment-form"),
        braintree{{ method}}Nonce = document.querySelector("#braintree{{ method }}-nonce");

    CommercePayments.onReady(function() {
        // Automatically setup and teardown the integration when choosing the braintree gateway
        var radios = document.querySelectorAll('input[name=choose_payment_method]');
        for (var i = 0; i < radios.length; i++) {
            var radio = radios[i];

            CommercePayments.addEventListener(radio, 'change', function(e) {
                if ( {
                    if ( == {{ method }}) {
                        // New drop in UI creation method
                            authorization: "{{ token }}",
                            container: "#c-braintree-payment-form-{{ method }}"
                        }, function(err, instance) {
                            braintree{{ method }} = instance;
                            teardownBraintree{{ method }} = !err;

                            braintree{{ method }}Form.addEventListener('submit', function(e) {
                                instance.requestPaymentMethod(function(err, payload) {
                                    braintree{{ method }}Nonce.setAttribute("name", "payment_method_nonce");
                                    braintree{{ method }}Nonce.value = payload.nonce;
                                    braintree{{ method }}Form.submit();
                    else if (teardownBraintree{{ method }}) {
                        braintree{{ method }}.teardown(function() {
                          braintree{{ method }}Nonce.removeAttribute("name");
                          teardownBraintree{{ method }} = false;

        // Load new drop in UI
        CommercePayments.loadAsynchronously('', function() {
            braintree{{ method }}Loaded = true;


This should work upgrading an existing website (tested using the default template), but be sure to test on your website first, especially if you’ve done any extensive theming to the payment method templates.

Mind if I copy this into Commerce 0.12? If it’s backwards compatible from a “config in = working payment out” with v2, that would be a great enhancement. :slight_smile:

That’s fine by me. It should be completely backwards compatible, since it is just changing the default braintree twig file. Everything is the same with the nonce it submits to Commerce.

On a related note, one helpful thing to have for Braintree, and perhaps other gateways, would be to also include the order object in the gateway’s twig files. For example, Apple Pay & Google Pay require passing the order amount in the dropin create:


That’s also a good idea. The Braintree dropin is quite flexible but does seem to need to be configured in code, so I’ll make some additional data available to support that. (Issue 289)

1 Like

The full order object is available as {{ order.field_name }} as of v0.11.3.

1 Like