Skip to main content

Browser UI contract

When a customer of yours reaches a screen that Wasp renders, that screen is not styled arbitrarily. It follows a contract, and this page is the part of that contract you can rely on and build against.

Three guarantees bind every Wasp-owned customer-facing browser surface. They are independent: a surface that satisfies some and not the others is not finished.

  1. It follows the theme you asked for, and the values are light | dark | system.
  2. It is responsive by default, at desktop, tablet, mobile portrait and mobile landscape.
  3. It stops taking payment actions while a payment is in flight, and releases only when the payment is genuinely retryable. See While a payment is in flight.

The theme values, and what each one means​

There are exactly three, and these are their names:

ValueWhat it does
lightForces the light palette, whatever the customer's device prefers
darkForces the dark palette, whatever the customer's device prefers
systemFollows the customer's own resolved device preference. This is the default

Those exact names, everywhere. Wasp does not accept auto, default, device, browser, colorMode or themeMode for this concept, and you will not find any of them in a Wasp surface or response. If you are mapping from a setting in your own application that uses one of those words, map it to one of the three above.

system is resolved when the screen renders, and the resolved answer is never stored. That matters to you in one practical way: if a customer changes their device preference part-way through a payment, the surface follows them. You do not need to do anything to make that happen, and you should not try to pre-resolve system yourself and send light or dark instead — doing so freezes the customer into whichever palette they happened to be in when your page loaded.

Where you set it​

You supply the theme once per journey, as an option when you start the checkout. Every Wasp-owned surface the customer reaches after that honours it, so a customer is never moved from dark to light and back partway through.

You do not set it per screen, and there is no separate call to change it.

Client-owned collection starts no Wasp checkout, so it supplies no theme. When one of its payments sends the customer to the Wasp-hosted authentication page, that page follows the customer's own device preference — system.

The exact option name and working code are in Light and dark, which opens with the Merchant API reference. This page is the contract; that page is the implementation.

Which surfaces honour it​

The contract binds the browser surfaces Wasp owns:

  • Hosted Checkout — the payment page Wasp hosts and renders.
  • Embedded Checkout — the controls the Checkout SDK renders inside your own page, in both Drop-in mode and Headless mode.
  • The Wasp-hosted authentication page.
  • Wasp-owned 3-D Secure screens — the surface around a challenge.

Two boundaries are worth stating plainly, because they are places the contract deliberately stops:

  • Google Pay uses Google's own supported button. Its variant follows the resolved theme — the dark button on a light surface, the light button on a dark one — but the button is Google's and Wasp does not restyle it.
  • Challenge content owned by a card issuer or its access control server is outside Wasp's styling control. Wasp themes the surface around it and never restyles or injects into the challenge itself. A 3-D Secure challenge may therefore not match your chosen palette, and that is correct behaviour rather than a defect.

Responsive behaviour you can rely on​

At every supported width — desktop, tablet and narrow desktop, mobile portrait and mobile landscape:

  • Normal content never requires horizontal page scrolling. If you see a Wasp surface scroll sideways at a normal width, that is a bug worth reporting.
  • Long text you supply wraps safely. Trading names, order references, error text and status text are expected to be long sometimes, and are handled rather than truncated into something misleading.
  • Controls stay touch-sized on touch layouts.
  • Narrow layouts tighten spacing. They do not turn into a stack of bulky cards, and they do not hide anything the wider layout shows.

You do not need to pass a width, a breakpoint or a device hint. There is no mobile-specific option to set, and no separate mobile surface to integrate.

While a payment is in flight​

A payment that Wasp has accepted but not decided can stay that way for some time — an authentication the customer has to complete, or one the issuer resolves in the background, is not instant. Throughout that window the reference is already committed, so a second submission cannot succeed and must not be offered.

The rule, for every surface:

accepted and unresolved
-> do not accept another payment submission
-> do not allow payment-affecting state to be changed
(the amount, the order, whether authentication is required)

terminal result
-> the attempt is spent; the controls stay closed

failed before it reached Wasp
-> nothing was committed; the customer may try again

That last line is the distinction that matters. A payment refused before it reached Wasp has spent nothing, so the controls come back. A payment Wasp accepted has spent the reference whatever happens next.

What Wasp guarantees​

SurfaceBehaviour
Hosted Checkout pageWasp owns the whole page. It hides the payment methods and disables its own controls from the moment an instrument is submitted, and shows the result when the payment is decided.
Wasp Checkout SDK — Drop-inThe SDK arranges the payment controls, so it locks them. They stop responding when the instrument is submitted, and are released only if the submission never reached Wasp.

What you are responsible for​

SurfaceYour obligation
Wasp Checkout SDK — HeadlessYou arranged the controls, so you disable them. The SDK deliberately does not reach into markup it did not create.
Client-owned collectionThe whole page is yours, including the pay button and anything that changes the order.

This is not a styling preference. A customer who can press Pay twice, or edit the amount while a payment runs against the old one, will eventually do both.

Anything on your page that can change what is being paid belongs in the same lock — not only the pay button. If your page lets the customer re-price the order, apply a discount, or start a different payment journey for the same order, those controls are payment-affecting and must close too.

Use whatever mechanism suits your page: disabled, pointer-events, an overlay. Add aria-busy="true" to the region so assistive technology reports the wait rather than a set of controls that silently do nothing.

Styling, and where the boundary is​

A Wasp-owned surface is styled by Wasp. The theme you choose decides its presentation, and that is the whole of the control you have over how it looks.

Do not restyle a Wasp surface from your own page. There is no supported way to override the appearance of Hosted Checkout or of the controls the SDK renders, and a page that reaches into them is relying on internal implementation detail that can change in any release. If a Wasp surface looks wrong next to your own page, that is worth reporting rather than working around.

What you can control is your own page, and the theme value you pass. If you want your surrounding page to sit comfortably beside an embedded Wasp surface, decide its appearance from the same choice you already made — you know whether you asked for light, dark, or system, and for system the customer's device preference is readable by your own page through ordinary prefers-color-scheme.

Branding a Hosted Checkout page

Setting your logo and your colours on a Hosted Checkout page is supported, and it is a separate mechanism: it is configured through the Merchant API rather than by styling the page. It is covered in the Hosted Checkout branding material, which opens with the Merchant API reference.

  • Light and dark — the option name, the values, and working code. Opens with the Merchant API reference.
  • Choose your integration — which of these surfaces you will actually be embedding.