'Slow loading time of Stripe Payment Element
I have a checkout page that primarily contains the new Stripe Payment Element and a PayPal payment button (from the Standard Checkout integration). The buttons load fast enough but the credit card form for the Payment Element takes over 5 seconds when loading locally via XAMPP, and I imagine the same would apply to the Google Pay and Apple Pay buttons if they rendered in testing mode. I expect that kind of speed in the development environment to translate to at least 2-3 seconds in production on a fast connection, which is still really slow.
Assuming that kind of loading speed is normal for the Stripe Payment Element, are there any strategies I can use to make it load faster?
In any case, I'd like to at least make the perceived loading speed faster by adding a spinner/preloader that displays until the form has loaded, which would also minimise the jarring content jump that currently occurs when the form loads (to be honest, I'm surprised that Stripe is fine with this UX in the first place). How would I integrate such a spinner into Stripe's client-side code?
Here is the client-side code in question in checkout.js, only slightly adapted from Stripe's Quickstart guide:
const stripe = Stripe(<PK_TEST_KEY>);
const fonts = [
{
cssSrc:
"https://fonts.googleapis.com/css2?family=Open+Sans:wght@300;400;500;600;700&display=swap",
},
];
const appearance = {
theme: "stripe",
labels: "floating",
variables: {
colorPrimary: "#000",
colorPrimaryText: "#fff",
colorText: "#fff",
fontFamily: "Open Sans, Segoe UI, sans-serif",
borderRadius: "4px",
fontSizeBase: "1em",
fontSizeXs: "0.7em",
fontWeightNormal: "400",
fontWeightMedium: "400",
fontWeightLight: "400",
},
};
let elements;
initialize();
checkStatus();
document
.querySelector("#payment-form")
.addEventListener("submit", handleSubmit);
// Fetches a payment intent and captures the client secret
async function initialize() {
const { clientSecret } = await fetch("/payment/stripe", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-CSRF-TOKEN": document.querySelector('input[name="_token"]').value,
},
}).then((r) => r.json());
elements = stripe.elements({ fonts, appearance, clientSecret });
const paymentElement = elements.create("payment");
paymentElement.mount("#payment-element");
}
async function handleSubmit(e) {
e.preventDefault();
setLoading(true);
const { error } = await stripe.confirmPayment({
elements,
confirmParams: {
// Make sure to change this to your payment completion page
return_url: "http://localhost/success",
},
});
// This point will only be reached if there is an immediate error when
// confirming the payment. Otherwise, your customer will be redirected to
// your `return_url`. For some payment methods like iDEAL, your customer will
// be redirected to an intermediate site first to authorize the payment, then
// redirected to the `return_url`.
if (error.type === "card_error" || error.type === "validation_error") {
showMessage(error.message);
} else {
showMessage("An unexpected error occured.");
}
setLoading(false);
}
// Fetches the payment intent status after payment submission
async function checkStatus() {
const clientSecret = new URLSearchParams(window.location.search).get(
"payment_intent_client_secret"
);
if (!clientSecret) {
return;
}
const { paymentIntent } = await stripe.retrievePaymentIntent(clientSecret);
switch (paymentIntent.status) {
case "succeeded":
showMessage("Payment succeeded!");
break;
case "processing":
showMessage("Your payment is processing.");
break;
case "requires_payment_method":
showMessage("Your payment was not successful, please try again.");
break;
default:
showMessage("Something went wrong.");
break;
}
}
// ------- UI helpers -------
function showMessage(messageText) {
const messageContainer = document.querySelector("#payment-message");
messageContainer.classList.remove("hidden");
messageContainer.textContent = messageText;
setTimeout(function () {
messageContainer.classList.add("hidden");
messageText.textContent = "";
}, 10000);
}
// Show a spinner on payment submission
function setLoading(isLoading) {
if (isLoading) {
// Disable the button and show a spinner
document.querySelector("#submit").disabled = true;
document.querySelector("#spinner").classList.remove("hidden");
document.querySelector("#button-text").classList.add("hidden");
} else {
document.querySelector("#submit").disabled = false;
document.querySelector("#spinner").classList.add("hidden");
document.querySelector("#button-text").classList.remove("hidden");
}
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|
