---
id: layout
title: Layout
summary: step_mode and field_order are behaviour, not CSS.
faces: ["public", "agent"]
section: front-end
group: Customise
order: 60
---
# Layout

`layout.step_mode: single_page` renders every field group in one form. `multi_step` groups the fields
into contact → billing → card with Next/Back, blocks advancing until the step is valid, moves focus to
the new step's first field and announces "Step 2 of 3: billing" to assistive technology.

`layout.field_order` sets BOTH the DOM order and the tab order of the fields it names — `email`,
`address_line1`, `postcode`, `country`, `card` (the card fields travel as one unit) — with omitted
fields appended in default order, except `country`: an omitted country goes straight after a named
`postcode`, its companion field. An unknown name is ignored (a console warning in test mode).

The embedded checkout draws no border and no rounded corners: the page around it supplies any
container.

The presentation also carries `brand` (`primary_colour`, `accent_colour`, `font_family`, `logo_url`),
`copy` (`cta_text` with `{amount}`, `trust_badge_text`, `footer_text`), `density` and `custom_css`.
The checkout's own type is self-hosted Inter and JetBrains Mono, served from `https://js.ripper.dev`,
with a system font fallback.
Custom CSS is checked before the checkout applies it: a rule that could reach the card fields, an
iframe or the universal selector is removed and reported to the console.

The theme for one call:

```js run id=layout-theme
const result = await ripper.collect({ amount: 4200, currency: 'GBP', appearance: { theme: 'light' } });
```
