A payment surface that configures itself
One deposit and withdrawal interface, embedded into many different client websites. Each client wants a different layout, a different density and a different set of payment methods — and none of them wants a bespoke build.
- Role
- Senior designer, then design lead
- Period
- Oct 2024 – present
- Working with
- Design, front end, back office
- Status
- In design and implementation
The problem was never the screen
Stripped to its barebones logic the product is close to a digital wallet: put money in, take money out, see your history of either. What makes it hard is that it is white label. It is embedded into someone else’s website, styled to someone else’s brand, and populated by whichever payment methods that client has enabled in a back office.
So the design question is not what the deposit screen looks like. It is:
- Which differences between clients are worth supporting as configuration?
- Which differences should the system decide, so a client cannot break the experience?
- Can a single component set absorb all of them without forking into separate products?
Every option we expose is a support cost forever and a way for a client to make the product worse. Every option we withhold is a sales objection. That trade is the actual design work.
How the widget is structured
The widget is a sequence of four stages: lobby, form, intermediary steps such as 2FA, and end flows (receipt or error). Every stage sits inside the same three-level wrapper, and each level owns exactly one thing.
| Level | Owns | Never owns |
|---|---|---|
| Shell | Window type, width, scroll, how it is dismissed | Anything about the content |
| Container | Component sizing, as a swap between two dimension token modes | Structure, order or what is visible |
| Content | The stage’s own screens | The window or the sizing |
One master shell and container setting applies to every stage. A stage can override it, but only where there is a known use case. Unlimited per-stage override multiplies the combinations someone has to test.
The configuration matrix
Five axes, chosen after mapping what clients had actually asked for against what the component architecture could carry without splitting into separate products.
| Axis | Options | Why it is configurable |
|---|---|---|
| Mode | 3 | Full page, right-hand drawer, or modal over a dimmed page. Depends entirely on how the host site is built, so it cannot be a system decision. |
| Density | 2 | Default and compact, driven by a spacing token scale rather than redrawn components. |
| Lobby layout | 4 | Clients have wildly different numbers of payment methods, and eight methods and forty methods want different layouts. |
| Form layout | 4 | Four arrangements of the same amount input, saved-card selector and bonus block. |
| Bonus offers | 2 | Modal or inline. A commercial decision about how hard to push offers, so it belongs to the client rather than to us. |
A third bonus presentation, vertical, was built for one client and is queued as a new value on this axis.
What stayed locked
The more useful half of the matrix is what is missing from it. Each of these was deliberately not exposed, and each one is a conversation I had to win.
- The shell. Deposit, withdrawal and history always sit in the same tab bar in the same position, and the compliance footer is always last. Clients can restyle it. They cannot rearrange it, because it is the only thing that stays constant while a user moves between payment methods.
- Step order. Method, then amount, then instrument, then confirm. Clients asked to reorder this. Reordering it breaks the validation model and every error state that depends on it.
- Spacing values. Density is a choice between two token sets, not a free numeric field. The moment spacing becomes an input, the design system stops being able to guarantee anything.
- Overlay type. Secondary overlays, such as saved cards or bonus selection, are sheets on mobile and modals on desktop. Never interchangeable, never a client choice.
- Error and empty presentation. A misconfigured lobby with no enabled methods still has to say something useful. Leaving that to the client guarantees a blank screen in production.
Form variants are presets, not designs
The four form variants look like four separate designs. Pulled apart, each one is a fixed combination of values across six independent axes. That reframing is what lets a new client request be absorbed without drawing a fifth form.
Each variant is a different combination of choices along the same few axes, such as how an amount is entered, how a saved method is picked and where the main action sits. Change one choice and you get a different form without redrawing the rest.
The rule that follows: a client customisation has to land as a new value on an existing axis. A new lobby layout and a vertical bonus layout were both built for a single client, and both ship as options any operator can switch on. If a request fits no axis, that is the signal to stop and decide whether a new axis is warranted, rather than slipping in a special case.
Arrangement and content are different questions
Operators choose how a form is arranged. They do not choose what is in it. That is decided by the payment method, and there are 50+ methods. So each method is assigned to one of a handful of typisations. Methods in the same typisation reuse the same blocks, rules and screen sequence, for deposits and withdrawals alike.
A rendered form is therefore three independent choices: form variant, typisation and direction. Neither of the first two is nested inside the other, so an account-based flow in Alpha and in Delta has the same blocks and the same rules, arranged differently.
| Typisation | What it is | Typical methods |
|---|---|---|
| Standard | An amount and a submit button. Nothing else. | 50+ methods |
| Card based | Saved card, add new card, delete card. | Credit and debit cards |
| Account based | Tied to a player account, with shared add, select and delete logic. | E-wallets, bank accounts |
| And more | A few others exist. Not shown here. | — |
The practical effect is that adding a payment method becomes an assignment rather than a design task. If a method fits no typisation, that is a decision point: extend one, or create a new one on purpose.
Responsive behaviour as a design decision
The four lobby layouts are not four breakpoint sets. Each is a different answer to the same question — how do you make a list of payment methods scannable — and the breakpoint behaviour follows from the answer.
Anatomy of the deposit form
Four elements, each more conditional than it looks.
- Amount input. Sits alongside preset amounts the client configures. Presets and field must stay in sync in both directions, and the field has to tolerate limits that differ per method and per user.
- Instrument selector. One container that is either a saved card, a chooser between several, or an invitation to add the first one. Three quite different states behind one affordance, because splitting them creates three layouts for one job.
- Bonus mechanic. Either a list of eligible bonus offers or a bonus code field for personalised codes, with a segmented switch between them. Eligibility depends on the amount input field, so the mechanic reacts while the user is still typing.
- Confirmation. After submission there is a gap while backend checks run, and only then a receipt. That gap is the riskiest moment in the product, and it gets a real state rather than a spinner over a frozen form.
Edge cases
Most of the design time went here rather than into the happy path.
- Methods that only support deposits, or only withdrawals, sharing one lobby without making the user discover the restriction after they have already committed to a choice.
- A lobby with nothing enabled, because someone misconfigured the back office.
- A backend check that fails after submission, when the money may or may not have moved.
- Amount limits that vary by method, so preset buttons can be invalid for the method just chosen.
- A bonus that becomes ineligible as the user edits the amount downward, after selecting it.
How it is documented
The system lives in three working documents, each answering one question:
- Design logic. What the building blocks are: tokens, components, their properties and states, and how they map to code.
- Layout logic. Which layout uses which components, and why, including a constraint matrix of which combinations are valid.
- Form logic. What each typisation contains, block by block, and which screens it owns from start to end.
Every claim in them carries a status: confirmed, draft or open. That is the point of the exercise. A guess that is not marked as a guess gets read as a decision, and by the time anyone notices it has been built.
What I would measure
This shipped without instrumentation. The team was structured to deliver requested features, not to evaluate them, and no success metrics were kept. I am not going to invent numbers for a portfolio. What I would have put in place, in priority order:
- Completion rate by payment method. The single number that says whether the lobby is helping, and the one that would settle the Rows-to-Grid argument with evidence instead of preference.
- Drop-off between lobby and form. Isolates method selection from method completion. High drop-off here means the lobby is promising something the form cannot deliver.
- Error rate on amount entry, split by whether presets were used. Directly tests whether the preset buttons do their job or just add noise.
- Saved-instrument reuse on repeat deposits. The clearest signal on whether the selector’s three states are legible.
- Time from submission to receipt, and abandonment inside that window. The gap I was most worried about, and the one I had no way to see.
Setting this up would not have been expensive. It was never asked for, and I did not push hard enough for it. That is the thing I would do differently.