The payments form that WooPayments generates and places on the checkout page is actually hosted on a separate PCI-compliant server. As such, applying styles to the payments form using custom CSS will not work as expected.
Instead, WooPayments provides a way for you to customize the payment form fields using simple JavaScript code.
Note that, in versions prior to WooPayments 10.6.0, customization was done via PHP and filter. That will no longer work as of 10.6.0 though. See how to migrate.
NOTE: We are unable to provide support for customizations under our Support Policy. If you need to customize a snippet beyond what is shown on this page, we suggest Codeable or a Certified WooExpert.
Clearing the cache
↑ Back to topBefore we explain how to customize the payment form fields, it’s important to know how WooPayments styles are cached. Otherwise you may make some changes to your code but not see those changes take effect on the checkout page.
In short, the payment form styles are computed in the browser and cached in your visitors’ localStorage. The cache automatically invalidates when:
- The WooPayments plugin is updated, or…
- The active theme is changed, or…
- Global styles or the theme color palette are modified.
If you need to manually force a recompute while developing your customization, you can clear the wcpay_appearance_* keys from localStorage in your browser’s developer tools, or simply switch your theme and immediately switch back.
Elements Appearance API
↑ Back to topThe form fields shown by WooPayments are embedded from Stripe’s servers. You need to use their Elements Appearance API to alter the styling of the fields. In WooPayments 10.6.0+, this is done via the wcpay_elements_appearance JavaScript event.
First, enqueue a JS file that registers a listener for wcpay_elements_appearance. For example, you could add the following to your theme’s functions.php or use a plugin like Code Snippets:
add_action( 'wp_enqueue_scripts', function () {
wp_enqueue_script(
'my-wcpay-appearance',
get_stylesheet_directory_uri() . '/my-wcpay-appearance.js',
[],
'1.0',
true
);
} );
Then, in my-wcpay-appearance.js (or whatever name you use), add a listener:
document.addEventListener( 'wcpay_elements_appearance', ( event ) => {
event.detail.appearance.rules['.Input'].color = '#333333';
} );
The event.detail object has two properties:
appearance: The Stripe Elements appearance object. You can mutate the object directly. No return value is required.elementsLocation: Where the elements are rendered. This must be one of:blocks_checkoutshortcode_checkoutbnpl_product_pagebnpl_classic_cartbnpl_cart_block
Some important notes to keep in mind:
- The event fires on cache miss only. This happens when the appearance is first computed or after cache invalidation due to a theme switch, plugin update, or style changes. It does not fire on every page load.
- The listener must be registered before WooPayments initializes checkout. Enqueuing your file at
wp_enqueue_scriptswith default priority (shown above) works. - To clear the cache and force a recompute, clear all the
wcpay_appearance_*keys from localStorage, or switch your theme and switch back.
There are three levels of customization available:
- Themes: Three basic, pre-built styles that may suit your website immediately.
- Variables: Allows you to control the appearance of many components at once.
- Rules: These provide complete control over every individual component.
Themes are the easiest to implement, but they may not match the exact look and feel of your site. To do that, you will likely need to use rules, although doing so involves a higher degree of complexity.
Themes
↑ Back to topStripe’s Elements Appearance API provides three pre-built themes as shown near the top of that page: stripe, night, and flat. These are good for quickly altering the appearance of the entire form.
For example, if your site has a darker background color, the night theme might work pretty well without further customization needed.
document.addEventListener( 'wcpay_elements_appearance', function ( event ) {
event.detail.appearance.theme = 'night';
} );

Variables
↑ Back to topBecause the style auto-detection results are added as rules, we strongly suggest using rules to customize the form fields. Using variables may not work as intended, since the rules will always override the less-specific variables.
For example, if you were to apply the following snippet:
document.addEventListener( 'wcpay_elements_appearance', function ( event ) {
var appearance = event.detail.appearance;
appearance.variables.fontFamily = 'serif';
appearance.variables.fontWeightNormal = 'bold';
} );
… the result may not apply to all the text in the form:

Again, this is because the auto-detected styling gets applied via rules, which are more specific than variables, so the rules “win.”
Rules
↑ Back to topThe rules method is very similar to CSS, in that you need to assign properties to certain selectors (form components, in this case) to achieve the desired outcome. This allows for very granular customization.
The form components that you can customize are the following:

Once you have determined which component you want to modify, you can use the following snippet as a template for your own code. Replace COMPONENT, PROPERTY, and VALUE with your desired modifications.
document.addEventListener( 'wcpay_elements_appearance', function ( event ) {
event.detail.appearance.rules['.COMPONENT'].PROPERTY = 'VALUE';
} );
For example, this snippet changes the color and weight of the label fonts:
document.addEventListener( 'wcpay_elements_appearance', function ( event ) {
event.detail.appearance.rules['.Label'].color = 'purple';
event.detail.appearance.rules['.Label'].fontWeight = 'bold';
} );
The result is like so:

You can expand on that by using the states, pseudo-classes, and pseudo-elements shown in Stripe’s documentation. They also have a list of available properties.
For example, to change the border of an invalid input, you could use this:
document.addEventListener( 'wcpay_elements_appearance', function ( event ) {
event.detail.appearance.rules['.Input--invalid'].border = 'thick double';
} );
The result is as expected:

Other options
↑ Back to topThere are two additional options you can set that affect the behavior of the form fields: labels and disableAnimations.
labels: eitheraboveorfloatingdisableAnimations: eithertrueorfalse
Setting a value for labels lets you change the position of the label relative to the input box. For example:
document.addEventListener( 'wcpay_elements_appearance', function ( event ) {
event.detail.appearance.labels = 'above';
} );
… will put the field label above the field. floating will insert it into the field.
Setting disableAnimations to true does exactly what it sounds like: turns off instances of animated movement in the payment form.
Style auto-detection
↑ Back to topBy default, WooPayments tries to detect some of the styles applied to the checkout page by your current theme, and then uses those styles on the payment form. This helps the form align more closely with your site’s existing design.
If you wish, you can prevent automatic style detection by returning a minimal appearance object:
document.addEventListener( 'wcpay_elements_appearance', function ( event ) {
// Replace the entire appearance with defaults to disable auto-detection.
event.detail.appearance.theme = 'stripe';
event.detail.appearance.variables = {};
event.detail.appearance.rules = {};
event.detail.appearance.labels = 'floating';
} );
However, we suggest that you not disable auto-styling, since it can make the payment form appear “broken”, or at least less readable. Here’s an example:
Migrating from PHP to JavaScript
↑ Back to topIf you were previously using the wcpay_elements_appearance filter to customize the payment form, that filter has been removed in WooPayments 10.6.0. You will need to migrate your customization to the JavaScript CustomEvent approach shown above.
Here how some example code may have looked using the old PHP-based method:
add_filter( 'wcpay_elements_appearance', function ( $appearance, $elements_location ) {
$appearance['rules']['.Input']['color'] = '#333333';
return $appearance;
}, 10, 2 );
And here’s how the change would be done in JavaScript:
document.addEventListener( 'wcpay_elements_appearance', function ( event ) {
event.detail.appearance.rules['.Input'].color = '#333333';
} );
Some important differences to keep in mind:
- Mutate in place. There is no return value. Modify the
event.detail.appearanceobject directly. - No transient clearing needed. The old transient caching mechanism has been removed. Changes apply on the next cache miss automatically.
- Second parameter renamed. The PHP filter’s
$elements_locationparameter is now available asevent.detail.elementsLocation.



