Skip to main content
Use the custom CSS field in the checkout editor to adjust the sale page and the result pages beyond what the editor fields cover. This page documents the style contract v1: the variables and hooks that stay stable across checkout updates, and the rules every stylesheet must follow.

How your CSS is applied

Your CSS applies only inside the checkout. :root, html and body target the checkout itself, and every other selector matches only elements inside it. Set the variables in :root and style blocks through the data-checkout-part hooks:
In a dark theme like this one, also darken the page background, with --checkout-background or the editor’s Background color field, or it stays light. Both apply on the sale page and the result pages, and the variable wins over the field. Part of the text sits on the page background and part on --checkout-surface, so pick a text colour that contrasts with both. The card fields follow these colours only in the infoproduct theme; in the shop and stepped themes they keep their own light look.

Variables you can set

Set these in :root. The default is what the theme’s fields render while the variable is unset. Other elements that read the variable keep their own tone until you set it: in the infoproduct theme, for example, fields use #d4d4d8 and cards use #e5e5e5. Setting the variable makes them match.

Variables you can read

These carry values from the editor fields. Use them inside var(...) in your rules, and change them in the editor.

Hooks

Each hook is an attribute on an existing block of the sale page. Target it with the attribute selector.
Guarded blocks hold what the buyer must see: fields, prices and the pay button. If your CSS hides or covers their content, the checkout switches your whole stylesheet off.

Result pages

The colour variables also apply on the pages the buyer sees after paying: Pix, card, boleto, subscription, the confirmation of each theme, the upsell and the post-checkout summary.
  • Page background: the same as on the sale page. --checkout-background wins when set; otherwise the editor’s Background color field applies, and with the field empty each page keeps its own tone, white or a very light grey.
  • Blocks with their own colours: these stay as they are, whatever your CSS sets:
    • the Pix QR code card, the code boxes and the copy buttons;
    • the boleto block, including its QR code in Peru;
    • the “waiting for confirmation” notices inside those blocks;
    • the upsell timer badge;
    • the map pin bubble;
    • the status panels.
  • Tertiary colour: when the editor sets it, it wins on the decline and apply buttons, so it needs contrast against the background your CSS sets.
  • Hooks: they are only guaranteed on the sale page. Where one also shows on a result page, it is outside the contract there.

What stays in the editor fields

Set these in the editor, not in CSS. The one exception is the page background:
  • primary colour
  • page background: the editor’s Background color field, which also applies on the result pages and which your CSS overrides when it sets --checkout-background
  • header colour
  • pay button colour and corner radius
  • font
  • logo, banner and images, since url() is not allowed in CSS

Styling rules

Every stylesheet must follow these rules. When something breaks one, the editor does not save and lists each problem with its line and column.
  • Size: up to 50,000 characters. The editor counts bytes, so accented characters take more than one. Once scoped to the checkout, the stylesheet is also capped at 150,000 characters.
  • At-rules: only @media, @supports, @container and @keyframes. Any other at-rule, such as @import, @font-face, @namespace, @layer, @page or @property, is rejected.
  • No url(), in any property.
  • Functions: only these are allowed. Any other, such as image-set(), image() or attr(), is rejected.
    • colours: rgb(), rgba(), hsl(), hsla(), hwb(), lab(), lch(), oklab(), oklch(), color(), color-mix(), light-dark()
    • variables and environment: var(), env()
    • math: calc(), -webkit-calc(), min(), max(), clamp(), round(), mod(), rem(), abs(), sign()
    • gradients: linear-gradient(), radial-gradient(), conic-gradient(), their repeating- versions, and the -webkit- prefixed forms of all of them
    • transforms: matrix(), matrix3d(), perspective(), rotate(), rotate3d(), rotateX(), rotateY(), rotateZ(), scale(), scale3d(), scaleX(), scaleY(), scaleZ(), skew(), skewX(), skewY(), translate(), translate3d(), translateX(), translateY(), translateZ()
    • filters: blur(), brightness(), contrast(), grayscale(), hue-rotate(), invert(), opacity(), saturate(), sepia()
    • shapes: inset(), circle(), ellipse(), polygon(), rect(), xywh()
    • timing, grid and counters: cubic-bezier(), steps(), minmax(), repeat(), fit-content(), counter(), counters()
  • Selectors: no :visited, no attribute selector on value, no selector that starts with a combinator, such as > a, and no ~ or + after :root, html or body.
  • No nesting: no &, and no rules or at-rules inside another rule.
  • Properties: behavior, -moz-binding and -webkit-box-reflect are rejected.
  • Reach and enlargement: nothing may paint far outside its element or enlarge it much. In the properties below, lengths go in px or rem (a rem counts as 16px), or 0, and scale factors as numbers. em, % lengths, viewport units, calc(), min(), max(), clamp() and var() are rejected there, whether as part of the value, as the colour or as the whole value.
    • box-shadow, text-shadow, outline, outline-width, outline-offset, the border-image outset, text-decoration, text-decoration-thickness, text-underline-offset, -webkit-text-stroke and their prefixed forms: each length up to 64px. To use a variable for the colour, set it in its own property, such as outline-color: var(--checkout-primary).
    • filter: the blur() radii add up to at most 64px, and drop-shadow() is rejected. Colour filters such as brightness() or grayscale() have no limit and accept var().
    • transform, scale and zoom: each declaration enlarges at most 1.1×, counting scale(), matrix() and skew(). translate() and rotate() have no limit and accept var() and calc(). perspective(), matrix3d() and any perspective other than none are rejected.
  • Guarded blocks: nothing that hides or covers the content of a guarded hook. The editor does not check this rule when saving: the checkout does, by switching your stylesheet off, as the warning under the hooks says.

Test before saving

1

Paste your CSS

Paste the stylesheet into the custom CSS field of the checkout editor.
2

Fix what the editor points out

Each problem shows its line and column. Save only works once the list is empty.
3

Check the preview

The editor preview applies the same CSS the published checkout serves. Check the blocks you changed on desktop and mobile.
4

Save

Save the configuration to publish the stylesheet.
If the preview applies your CSS and goes back to the default a moment later, the checkout switched your stylesheet off because a field, a price or the pay button became invisible or lost contrast. The typical case is light text on a page background that is still light: set --checkout-background or darken the Background color field.

Use with an AI

To reproduce the look of another checkout, copy the prompt below into the AI you use. Replace everything in brackets with the reference checkout and your current editor values, and attach screenshots of the reference. The answer has two parts: the values go into the editor fields and the CSS into the custom CSS field. Then test it in the preview as above.

Utility classes

Selectors written against the checkout’s utility classes, such as .bg-white, still work, but they are not part of the contract and can change in any checkout update. Prefer the hooks and variables on this page.
This page documents style contract v1. A change to the variables or hooks bumps the contract version.