Jithin Raj  P R
Jithin Raj P R

Reputation: 6797

Custom theme for Payment Request Button [Stripe]

Usually, we use a theme which was provided stripe like the following.

style: {
  paymentRequestButton: {
    theme: "light-outline"
  }
}

They have also provided some theme's like 'dark' | 'light' | 'light-outline'

My question is can we create a custom theme for this button.? eg: a blue colour theme

Or is there any workaround or script hack for changing the color of the button.?

Upvotes: 11

Views: 7272

Answers (3)

Chris Pratt
Chris Pratt

Reputation: 239290

It is not possible to custom style the payment request button. However, you can use Stripe's payment request API with a custom button. The documentation only hints at this. Also, this should still be 100% PCI-compliant, as your application still never sees or touches any credit card information. I have a CodePen you can refer to as an example.

Essentially, just create whatever kind of button you want on your page. Then, bind the click event to paymentRequest.show, where paymentRequest is an instance of Stripe's PaymentRequest. For example:

let stripe = Stripe('pk_test_abc123');
let paymentRequest = stripe.paymentRequest({
    ...
});
let button = document.getElementById('awesome-custom-button');
button.addEventListener('click', paymentRequest.show);

Then, when you get the token, simply call ev.complete('success') before the end of the delegate function. For example:

paymentRequest.on('token', function (ev) {
    // do whatever with the token
    ev.complete('success');
});

The only slight hangup is that Apple dictates that the Apple Pay button must be styled a certain way, according to their HIG. The Stripe Elements payment request button handles this out of the box, but since you're no longer using the Elements button with this approach, you simply need to change your custom button manually. There's a number of ways you can do that. In my example code, I'm using Bootstrap and Fontawesome, so in the canMakePayment delegate function:

if (result.applePay) {
    button.className = 'btn btn-dark';
    button.style.backgroundColor = '#000';
    button.querySelector('.default').style.display = 'none';
    button.querySelector('.applepay').style.display = 'inline';
}

In my button HTML, I have a span with a "default" class that contains the normal button content and another span with an "applepay" class that is hidden initially and contains the following HTML:

<span class="fa-lg">
    <i class="fab fa-apple-pay" data-fa-transform="grow-12"></i>
</span>
<span class="sr-only">Purchase with Apple Pay</span>

Upvotes: 9

tao
tao

Reputation: 90068

Reading Step 3 of Payment Request Button implementation steps, it is obvious the element has id: #payment-request-button.

Haven't worked with Stripe and I don't know if it's a <button> or a more complex HTML markup structure and I also read somewhere in their docs they do not guarantee maintaining the HTML structure of their elements.

Anyway, here are a few things to keep in mind when aiming this type of intervention: most importantly, develop in steps:

  1. Find a solution that works for the time being. Ideally, it should be something that degrades/fails gracefully and silently (no public facing errors)
  2. Maximize ability to withstand minor modifications in markup from Stripe

Also, keep your source files so you can easily adapt your solution to any markup breaking changes from Stripe so you can provide a fix when it stops working.

If you rely on CSS (recommended), you should inspect the currently rendered markup and find out what are the currently applying selectors. Simply writing stronger selectors should be enough. If styles are being applied via JavaScript by Stripe, chances are you will need to use !important in your CSS. Of course, you should avoid it as much as possible, or at least thoroughly test on as many devices as you can get your hands on.
As a rule of thumb, !important is quite bad in CSS. It's a very powerful hammer and most times it breaks delicate things (i.e.: responsiveness on touch devices).

Alternatively, if you rely on JavaScript to do the styling, you might want to play around with setTimeout() and determine the proper amount of miliseconds to wait before triggering your changes after the prButton.mount() method was called. Test on multiple devices. I advise against this method as it's more error prone and more difficult to control: you want to time your changes just after the element was built but (ideally) before it gets rendered. Of course, there are workarounds, such as hide or fade it until your changes are applied.


Note: This is not an easy task and nobody (except Stripe themselves, by providing a proper method) can guarantee you a bullet-proof solution so I thought laying out the principles on how to approach it might have more value on short and long term than trying to get Stripe working on a test/dev account and provide a particular solution which might stop working the next day, when Stripe change their markup.

Upvotes: 0

Henrik Joreteg
Henrik Joreteg

Reputation: 1736

I've been trying to do this as well, but the reference docs here at the very bottom seem to indicate the answer is "no".

Looks like beyond a type, and theme the only thing you can set is a height: https://stripe.com/docs/stripe-js/reference#element-options

(Screenshot of relevant section below, in case it changes)

enter image description here

Upvotes: 6

Related Questions