Skip to main content
HomeBlogDesigning a crypto product that holds together across mobile and web: one system, two density tokens

Designing a crypto product that holds together across mobile and web: one system, two density tokens

Most crypto UIs fail the responsive test on first principles — the mobile app feels nothing like the web app. Here's the design-system move that fixed it on Enrichplay: two density tokens carrying the same components across breakpoints.

Masfa Zulfiqar — UI/UX Designer
UI/UX Designer · Karachi
Design SystemsPublished13 min read
Designing a crypto product that holds together across mobile and web: one system, two density tokens hero

Abdul Ahad Magsi came to me with a crypto product idea and a single non-negotiable: it had to live on a phone and on the web, and both had to feel like the same product. Not a mobile site and a desktop site. One product, two viewports, one identity. That's a sentence founders say all the time. It's a much harder thing to actually deliver — especially in crypto, where most products visibly break in half the moment you resize the browser.

The hard observation underneath the brief is that crypto products are usually designed twice. The mobile app gets a designer. The web dashboard gets a different designer, or the same designer in a different mode of thinking, weeks later. The user opens the app on their phone in the morning, opens the dashboard on their laptop in the afternoon, and the two surfaces feel like products from two different companies. Different visual hierarchy. Different action placement. Different density. Sometimes different language for the same thing. Their mental model breaks every time they switch device.

That's the failure mode this post is about. I want to walk through the design-system move that fixed it on Enrichplay — two density tokens, one component library, composition handling the breakpoint. The technical centrepiece is small. The discipline around it is what does the work.

If you're a founder weighing what "responsive" should actually mean for your product, or a designer trying to keep a system from drifting between breakpoints, this is the writeup of how that played out on a real engagement.

Why most responsive crypto products feel like two products

Before I get to the fix, I want to be specific about the failure. "Two products" isn't a vibe — it's a set of observable seams that show up in almost every crypto UI I open on both surfaces.

The first seam is visual hierarchy. On mobile, the balance sits at the top in a 32px figure. On web, the same balance lives inside a card in a sidebar, smaller, surrounded by chrome. The user's eye lands somewhere different on each surface for the same piece of information. That's a violation of the contract responsive design implicitly makes — the most important thing stays the most important thing.

The second seam is action placement. Send, receive, swap. On mobile these are a bottom-anchored bar at thumb level. On web they're often scattered: send inside a dropdown menu, receive in the header, swap on a separate page. The user has to relearn the product's verbs every time they switch device. Crypto, of all categories, can't afford this — the verbs are the product.

The third seam is density. Mobile is necessarily compact. But desktop, given infinite pixels, drifts toward "more is more": denser tables, more columns, more chrome, more chart. The same transaction history that read as a calm list on mobile reads as a Bloomberg terminal on web. The product changes character across surfaces. Trust drops on the busier one.

The fourth seam is language. "Send" on mobile becomes "Transfer" on web. "Asset" becomes "Token." "Network" becomes "Chain." Each of those substitutions is defensible in isolation. Together, the product loses its tone of voice exactly when the user is most exposed to it.

The reason these seams exist is rarely incompetence. It's that mobile-first design treats the web layout as an afterthought (and vice versa), and there's no shared spine forcing the two surfaces to make the same decisions. The fix isn't talent. It's order of operations.

System before screens

The order matters more than anything else in this writeup. I built the design system before designing any individual screen for Enrichplay. That sequencing is the move that makes everything downstream cheap.

When the tokens and components exist first, every screen afterwards is a composition of things that already exist. Composition decisions are smaller than design decisions. They live inside a vocabulary the system already provides. The designer isn't reinventing what a transaction row looks like every time one shows up; they're deciding where a TxRow sits relative to its surroundings.

The token list on Enrichplay is short on purpose. Surface colours, accent, warning, ink. A display type with tabular figures for amounts. A body type that reads at small sizes. A card radius. Two density tokens. That's most of it. The full list is in the case study if you want to see the whole grid.

The component library is similarly small: AssetCard, BalanceHeader, TxRow, NumberBlock, ActionRail, ConfirmSheet, NetworkBadge. Seven primitives. Every screen in the product is built from them. The deliverable is the system; the screens are evidence the system works.

What that ordering buys you is consistency for free. The mobile dashboard and the web dashboard aren't two separate design problems — they're two compositions of the same components. The designer's job stops being "design the dashboard for each breakpoint" and starts being "decide how these seven components arrange themselves at this viewport." Those are categorically different problems. The second one is much smaller, and the answers are much more defensible.

The order also forces honesty about what's actually in the product. If a screen needs a new pattern that the system doesn't have, you have to decide: is this primitive missing from the system, or is this screen wrong? Most of the time, the screen is wrong. Occasionally the system is genuinely missing something, and you add it as a token or a component, not as a one-off. Either way, the system stays coherent.

The density-token move that did most of the work

The technical centrepiece of the responsive system is two tokens: spacing/density-mobile and spacing/density-web. Mobile is compact — an 8/12/16/24 scale. Web is spacious — 12/16/24/32. Same scale shape, different breathing room. Each component reads its current density token from context. The system handles the breakpoint, the layout inherits.

That's the whole move. It sounds small. It carries an unreasonable amount of weight.

What it replaces is the alternative most teams default to: manually respacing every component at every breakpoint. A balance card on mobile gets one set of padding values. The same card on web gets a different set, hand-tuned in a separate Figma frame. By the time the system has fifteen components, the designer is maintaining fifteen pairs of spacing decisions. They drift. They get inconsistent. A new component gets added and someone forgets to define its web spacing, so it inherits mobile padding by accident and looks cramped at 1440px. The system has become a maintenance burden instead of a leverage point.

Two density tokens collapse all of that into one decision: what does breathing room mean at this breakpoint? Define it once, apply it system-wide. Every component that's already aware of the density token automatically scales. New components join the system by referencing the tokens, not by re-deciding spacing from scratch.

The other thing this buys you is the ability to argue for consistency as a property of the system rather than the discipline of the designer. The same TxRow rendered with spacing/density-mobile and with spacing/density-web is provably the same component, breathing differently. It's not "the mobile version" and "the web version" — it's one row, two ambient density states. The component's identity is preserved across breakpoints by construction, not by remembering.

There's a smaller move that pairs with this and shouldn't be skipped. The type system uses tabular figures for numerical display (the NumberBlock component renders amounts in a tabular font variant). At any breakpoint, at any density, the figures stay aligned. The decimal points line up across rows. The amount doesn't reflow during a live update because every digit takes the same width. Tabular numerics are the unsung hero of crypto typography. Most products skip them. The cost is dignity.

Together — two density tokens, tabular figures, components that read density from context — the system can survive a viewport resize without the designer touching anything. That's the bar responsive design should be held to, and it's the bar most crypto products don't clear.

What changes between breakpoints — and what doesn't

The principle I held throughout the build: components don't change between breakpoints — composition does. A balance card on mobile is the same component as a balance card on web. A transaction row is the same row. The action rail is the same rail. What changes is what sits next to them, and where they sit on the screen.

That principle is easier to state than to maintain. The temptation, at every breakpoint, is to "improve" a component for the new viewport — give the web version of TxRow an extra column because there's room, give the mobile version of BalanceHeader a tighter layout because there isn't. Each of those improvements feels right in isolation. Together they fork the component into two components that share a name. Six months later they've drifted into two genuinely different things. The system is gone.

Here's the actual breakdown of what holds vs. what flexes across Enrichplay's breakpoints:

ElementMobile (375px)Web (1440px)What's holding
BalanceHeaderFull-width, top of screenTop-left of a three-column dashboardSame component, same internal hierarchy, density token loosens
ActionRailBottom-anchored bar, thumb-levelSide rail at the left edge, mouse-levelSame component, anchor point changes per viewport
TxRowSingle column list below balanceTwo-column list to the right of balanceIdentical row, frame around it carries the difference
AssetCardStack of cards, full widthGrid of tiles, 2–3 wideSame card, layout container shifts from stack to grid
NumberBlockTabular figures, large sizeTabular figures, same large sizeIdentical — amounts read identically across surfaces

The hardest call across breakpoints was the transaction list. On mobile, every row needs to feel like a complete unit — amount, recipient, status, time, all visible in one glance because there's no surrounding context to lean on. On web, the same row can give up a column to its neighbours because the rest of the dashboard is doing some of the work. I held the row identical across both and let the frame around it carry the difference. Less to debug. Less to maintain. The row stays the row.

The ActionRail move is worth lingering on. It's the component that most visibly changes position across breakpoints — bottom bar on mobile, side rail on web. But it's the same component, with the same three verbs (Send, Receive, Swap), the same icons, the same hierarchy. What changes is where the component anchors itself in the viewport, because thumb position and mouse position are different problems. The verbs and their order don't change. The user learns them once.

A worked example: the send flow

The send flow is the screen where the system's discipline matters most, because sending crypto is the action with the highest cost-of-error in the product. Get it wrong and the user loses money irreversibly.

I sketched three variants. Here's the comparison:

VariantPatternWhy consideredOutcome
v1All on one screenFewest taps, single-shot completionKilled — under stress, too many unrelated decisions side-by-side. Recipient, amount, network, memo all competing for the same visual weight.
v2Chunked, two stepsStep 1: recipient + amount. Step 2: network + memo + review sheet before signingChosen. Each step owns one cluster of related decisions.
v3Chat-style sendRecipient as a "conversation" — message a contact to sendKilled — the messenger metaphor over-promised on capabilities (chat, history, social context) that don't exist in the product yet.

The v2 chunking is justifiable on the same principle that drives form chunking generally: decisions cluster naturally, and forcing related decisions into one step while separating unrelated ones reduces the cognitive load at each moment of commitment. Recipient and amount go together — who and how much. Network and memo go together — which chain and any note for the receiver. Review-and-sign sits as a separate moment so the user has a clear visual contract that "I am now committing this transaction."

The v1 all-on-one-screen variant felt efficient until I imagined doing it under stress. The user is sending a real amount to a real person and their thumb is hovering. Five decisions side-by-side compete for the same attention. The user can't tell which field they last touched. They can't tell what they're about to commit. The visual density of "fewer screens" became cognitive density at exactly the moment the user needed clarity.

The v3 chat-style send was the most interesting reject. The messenger metaphor reads as friendly and modern. But the product doesn't have a chat surface, a contact list with rich social signals, or any sense of "conversation history" with recipients. The metaphor would have written a cheque the product couldn't cash. Worse, it would have softened the gravity of an irreversible action by framing it as casual messaging. Wrong tone for the moment.

The chosen v2 pairs with the ConfirmSheet component as the final gate. The sheet states the consequence in plain language — you're sending X amount of Y on Z network to this address — before the user can sign. That's where the system's NetworkBadge token earns its place too: the chain is always visible, always near the amount, at every step of the flow. Wrong-network sends are the single most common irreversible failure in crypto. Surfacing the network at every step makes it the user's responsibility to mis-send rather than the interface's.

Carrying it forward

The two-density-token move is small enough to feel like nothing on the way in and consequential enough to feel like everything on the way out. It's the move I'd carry forward into any product that has to ship across mobile and web from the same system.

The wider principle is the one underneath it: build the system before the screens, and the screens become compositions. A composition is a much smaller decision than a layout. It stays inside a vocabulary the system already provides. It's defensible across the table from a sceptical engineer because every piece of it traces back to a token or a component that exists for a reason.

If you want to see the full token grid, the component library, and the responsive variants in context, the Enrichplay case study has the deck. The other writeup in this voice — how I anchored a UX audit to four named laws — sits next to it as the process companion.

And if you're a founder thinking about a responsive product where mobile and web genuinely need to feel like one thing, the services page covers what an engagement looks like; the contact page has booking. Intro calls are free and short.

Masfa Zulfiqar — UI/UX Designer
Written by
Masfa Zulfiqar
UI/UX Designer · Karachi, Pakistan

Masfa Zulfiqar is a UI/UX designer in Karachi, Pakistan with 4+ years of first-hand experience shipping mobile apps and responsive products for founder-led startups. Her recent work includes Painted Juttay (hand-painted juttis ecommerce for founder Muzammil Ahmed), Enrichplay (a responsive crypto product for founder Abdul Ahad Magsi), and a self-directed UX audit of Take Therapy grounded in named UX laws (Hick's, Fitts', Doherty, Nielsen-5).

Available now · 1 slot open

Got a thing to ship?

Or email me
Based in
Karachi, PakistanUTC+5