Custom checkout CSS
Extend the checkout with custom CSS. Automatic sanitization to block XSS, MITM and payment flow bypass.
TLDR: from the dashboard you can inject custom CSS into the checkout to align it pixel-perfectly to your brand. Below: common selectors, what our sanitizer blocks, and ready-to-use snippets.
Where
Dashboard โ Checkout โ Custom CSS (editor at the bottom of the page). Available to all merchants, no plan gating.
What you can do
Work with the standard selectors of the classes we expose in the checkout markup. Examples:
Change font
body {
font-family: 'Helvetica Neue', -apple-system, sans-serif;
}External @font-face declarations are blocked by the sanitizer (see below). Use system fonts, or load the font on your store and declare it via @import on a domain you control โ it'll still be stripped. For now: stick to system fonts.
Rounded Pay button
button[type="submit"] {
border-radius: 999px;
font-weight: 700;
}Flat cards
.card, .section {
border: none;
box-shadow: 0 1px 2px rgba(0,0,0,0.06);
background-color: #FAFAFA;
}Apple-style inputs
input {
border: 1px solid #D1D5DB;
border-radius: 12px;
}
input:focus {
border-color: #000;
box-shadow: 0 0 0 4px rgba(0,0,0,0.04);
}Hide elements on mobile
@media (max-width: 640px) {
.trust-badges { display: none; }
}What the sanitizer blocks
Our sanitizeCustomCss strips these patterns at runtime (for security, no errors on save):
| Pattern | Behavior |
|---|---|
url(...) of any kind | Replaced with url("about:blank") โ closes off data:/file:/extension/font-face vectors |
@import, @charset, @font-face, @namespace, @document, @supports url() | Completely removed |
expression(...) | Blocked (legacy IE XSS) |
[attr=...] selectors | Blocked (including aria-/data-* set by autofill) |
:has(), :is(), :where() | Blocked (can synthesize indirect matches on attributes) |
CSS variables that cascade url() (--x: url(...)) | Blocked |
javascript: scheme | Stripped |
This is a runtime blacklist: CSS is saved as-is but the client sanitizes it before injecting it into the checkout's <style>.
Best practices
- Never override the submit button or the Whop iframe: you risk breaking the payment flow
- !important everywhere makes CSS hard to maintain. Use proper specificity
- Always test on 375px mobile (iPhone SE): the checkout is mobile-first
infiniteanimations drain mobile battery
Test
- Edit the CSS in Dashboard โ Checkout โ Custom CSS โ Save
- Open your test checkout in incognito (e.g. via onboarding "Preview" or by clicking a product in your store)
- DevTools โ Toggle device toolbar โ iPhone SE to validate mobile
- Verify that:
- Payment button โฅ 44px tall (touch target)
- Inputs aren't pushed outside the viewport
- Order summary is readable
Rollback
If you break the checkout (e.g. CSS that hides the Pay button):
- Dashboard โ Checkout โ empty the custom CSS field โ Save