Use a custom font with a Stripe Element input
In the past months, I worked a lot on creating a fully customized subscription workflow in my daily job at Bridge.audio. I had to implement this workflow with Stripe Elements and after reading Stripe’s documentation, all I was able to get was this :
As user I was able to fill my credit card information but the style of my input was not as I expected it to be…
The font of the Credit card input doesn’t match the font of the other fields.
A Stripe Element input is an iFrame
Indeed, the input Credit card is an iFrame, it’s for security reasons so that critical go straight to Stripe servers. And that’s why the font is not correctly displayed on the input, iFrames must load their own resources. So if you want to use a custom font, you have to load it specifically for the Credit card input.
Of course, Stripe have a solution for that, I found some interesting stuff in their massive documentation, you must use a CustomFontSource
object when creating your element, so you need to add this params when you create your element :
{
family: 'myFont',
src: `url(https://example.com/assets/myFont.woff)`,
weight: '500'
}
But I didn’t find the documentation to be enough explanatory and the error displayed in the console is kind of cryptic :
My working example
If like me you struggle with this, I hope this snippet will save you some time, you MUST respect the following rules :
- Use an absolute URL with the domain name,
- Encapsulate the font url into a
url()
, - Make your font accessible from another domain.
There is one thing I didn’t mention already, once you’ve loaded the font you still have to apply the font to your element.Here is my first working example, with a static font :
const stripe = window.Stripe("YOUR_PRIVATE_PK_KEY");
const myFontAbsoluteUrl = "https://example.com/static/myfont.woff"
const elements = stripe.elements({
fonts: [
{
family: 'myFont',
src: `url(${myFontAbsoluteUrl})`,
weight: '500'
}
]
});
const cardElement = elements.create('card', {
style: {
base: {
fontWeight: 500,
fontFamily: 'myFont',
fontSize: '14px',
fontSmoothing: 'antialiased',
}
}
});
With this snippet, here is my final result :
The font is the same for all my inputs ! Yay…
Other things you might consider
If the previous snippet didn’t work as expected, there are still 2 things that can help you.
Take care of your font cache busting
If you use a JS builder on your project, you may encounter another issue. The filename of your font is dynamic and changes on every build be cause of cache busting.
So you have to load your font in your code and so that your builder will replace the url with the real one after building. With Vite, I had to do something like that :
import myFont from "./some/path/myFont.woff"
[...]
const elements = stripe.elements({
fonts: [
{
family: 'myFont',
src: `url("${document.location.origin}${myFont.toString()}")`,
weight: '500'
}
]
});
Generally the builder will generate a url starting with a slash, you’ll have to add the origin domain before manually.
Add missing CORS header on your server
Last point, if your server CORS headers are not configured to allow the download of your font, you might still encounter issue.
As I explained earlier, Stripe use an iFrame and it’s loading content from another domain : «somedomain.stripe.com». To load the font, your server must add the header Access-Control-Allow-Origin
.
Here is how we did it on our server, we allow our font to be downloaded from everywhere:
if ($request_uri ~* \.(?:eot|otf|ttf|woff|woff2)) {
add_header Access-Control-Allow-Origin "example.com";
}
It’s not a perfect solution as it allows anoybody from anywhere to download our fonts from anywhere but as our font url are cache bursted, it’s a small issue that we can live with…
Conclusion
And we are done here ! I hope that with all these advices, you’ll be able to easily use a custom font in your Stripe Element.