[{"data":1,"prerenderedAt":245},["ShallowReactive",2],{"writing-defi-swap-ui":3},{"id":4,"title":5,"body":6,"category":233,"date":234,"description":235,"extension":236,"i18nKey":237,"meta":238,"navigation":239,"path":240,"readingTime":241,"seo":242,"stem":243,"__hash__":244},"writing\u002Fwriting\u002Fdefi-swap-ui.md","Building a DeFi swap UI users don't fear",{"type":7,"value":8,"toc":224},"minimark",[9,13,20,25,28,35,57,61,64,70,81,87,98,102,105,159,163,170,201,204,208,215],[10,11,12],"p",{},"Swapping tokens is, functionally, a two-input form. Yet most swap UIs manage to look like a Bloomberg terminal having a bad day: exchange rates, price impact, slippage settings, route diagrams, gas estimates, USD values, pool fees — all rendered at once, all at the same visual volume.",[10,14,15,16],{},"The audience problem makes it worse. A DeFi interface serves two users at the same URL: someone making their third swap ever, and someone who checks price impact to two decimals. Working on CaveSwap, the design question was never \"how do we show all this data\" — it was ",[17,18,19],"strong",{},"\"who needs which number, and when?\"",[21,22,24],"h2",{"id":23},"fear-comes-from-irreversibility-not-complexity","Fear comes from irreversibility, not complexity",[10,26,27],{},"Web apps train people that mistakes are undoable. Crypto breaks that contract: a confirmed transaction is final, and users know it. That background anxiety changes how they read your UI — every ambiguous label becomes a threat, every spinning loader a small crisis.",[10,29,30,31,34],{},"So the design goal isn't \"simple\". It's ",[17,32,33],{},"legible under stress",". A user about to move real money re-reads everything, and the interface has to survive that suspicious second reading. Concretely:",[36,37,38,45,51],"ul",{},[39,40,41,44],"li",{},[17,42,43],{},"The primary action names what it does."," \"Swap ETH for USDC\" beats \"Confirm\". If the button can say the consequence, it should.",[39,46,47,50],{},[17,48,49],{},"The confirm step is a sentence, not a table."," \"You pay 0.5 ETH. You receive at least 1,643.20 USDC. Rate expires in 24s.\" A human sentence with a worst-case number beats twelve rows of key–value pairs.",[39,52,53,56],{},[17,54,55],{},"The worst case is explicit."," \"At least\" is doing real work up there — it converts slippage from a setting into a promise.",[21,58,60],{"id":59},"progressive-disclosure-the-volume-knob","Progressive disclosure: the volume knob",[10,62,63],{},"The CaveSwap redesign boiled down to sorting every data point into three tiers:",[10,65,66,69],{},[17,67,68],{},"Tier 1 — always visible:"," the two amounts, the tokens, your balance of each, the primary button. That's it. This is the whole interface for the 90% case.",[10,71,72,75,76,80],{},[17,73,74],{},"Tier 2 — one tap away:"," rate, price impact, minimum received, network fee, route. Collapsed into a single summary row (\"1 ETH ≈ 3,291 USDC · details\") that expands. Power users open it every time and that's fine — ",[77,78,79],"em",{},"opening it is a choice",", and the beginner never pays the cognitive cost.",[10,82,83,86],{},[17,84,85],{},"Tier 3 — settings:"," slippage tolerance, deadline, expert toggles. Behind a gear icon, with defaults good enough that most users never look.",[10,88,89,90,93,94,97],{},"The exception that proves the rule: ",[17,91,92],{},"warnings jump tiers."," Price impact lives in tier 2 — until it exceeds a threshold, at which point it moves into tier 1, colored, next to the button it's warning you about (\"Price impact 4.8% — you're trading into thin liquidity\"). Information earns screen space by being ",[77,95,96],{},"currently important",", not by existing.",[21,99,101],{"id":100},"numbers-are-a-ui-component","Numbers are a UI component",[10,103,104],{},"DeFi numbers are user-hostile by default: 18 decimals, scientific notation, dust balances. Formatting them is real design work:",[36,106,107,122,136,153],{},[39,108,109,112,113,117,118,121],{},[17,110,111],{},"Balances truncate, inputs don't."," Display ",[114,115,116],"code",{},"1.2847 ETH",", but tapping ",[17,119,120],{},"Max"," fills the input with the exact value. Truncate an input and you've either blocked a full swap or invented dust.",[39,123,124,127,128,131,132,135],{},[17,125,126],{},"Show fiat next to crypto."," ",[114,129,130],{},"0.5 ETH ($1,645)"," — the dollar value is what catches the extra zero ",[77,133,134],{},"before"," the confirm screen does.",[39,137,138,127,141,144,145,148,149,152],{},[17,139,140],{},"Significant digits scale with magnitude.",[114,142,143],{},"1,643.20"," and ",[114,146,147],{},"0.000032"," are both four significant digits doing their job; ",[114,150,151],{},"1,643.204818"," is noise wearing a suit.",[39,154,155,158],{},[17,156,157],{},"Never let a number silently be stale."," Quotes age. Show it: \"rate updates in 12s\", and re-quote before confirm if it expired. A user who swaps on a dead quote and gets a worse fill will — correctly — blame you.",[21,160,162],{"id":161},"transaction-states-that-read-like-a-story","Transaction states that read like a story",[10,164,165,166,169],{},"Between \"I clicked\" and \"it's done\" lives the most anxious UX in software. The states need to be ",[77,167,168],{},"narrated",":",[171,172,173,179,189,195],"ol",{},[39,174,175,178],{},[17,176,177],{},"Waiting for wallet"," — \"Confirm in your wallet\" with the wallet's icon. The #1 confusion moment: the action moved to another window and the UI should say so.",[39,180,181,184,185,188],{},[17,182,183],{},"Pending"," — hash truncated, explorer link, elapsed time. The explorer link matters even for users who never click it: ",[77,186,187],{},"being checkable"," is what makes the state trustworthy.",[39,190,191,194],{},[17,192,193],{},"Confirmed"," — what actually happened, with final amounts: \"Swapped 0.5 ETH → 1,650.80 USDC\". Received amount can differ from the quote; show the real number.",[39,196,197,200],{},[17,198,199],{},"Failed"," — translated. \"Transaction reverted: slippage exceeded — the price moved more than 0.5% while your transaction was pending. Try again or raise your tolerance.\" Raw RPC errors are not messages, they're stack traces with gas fees.",[10,202,203],{},"And when the user comes back later: pending transactions survive a page refresh. Losing track of an in-flight transaction is the single fastest way to teach someone your app can't be trusted with money.",[21,205,207],{"id":206},"restraint-is-the-feature","Restraint is the feature",[10,209,210,211,214],{},"The uncomfortable part of this work is that it mostly consists of ",[77,212,213],{},"removing"," things — data, borders, colors, urgency. Every element you delete makes the remaining ones more legible, and in an interface where users are already scared, legibility is the entire game. The power user loses nothing (tier 2 is one tap away); the new user gains the ability to complete a swap without feeling like they're defusing something.",[10,216,217,218,223],{},"I design and build these interfaces end to end — Vue\u002FNuxt, Wagmi\u002FViem, from the Figma exploration to the deployed app. If your protocol's UI is scaring users away, ",[219,220,222],"a",{"href":221},"\u002F#contact","I can help",".",{"title":225,"searchDepth":226,"depth":226,"links":227},"",2,[228,229,230,231,232],{"id":23,"depth":226,"text":24},{"id":59,"depth":226,"text":60},{"id":100,"depth":226,"text":101},{"id":161,"depth":226,"text":162},{"id":206,"depth":226,"text":207},"Web3","2026-08-03","What I learned reducing visual noise in CaveSwap — progressive disclosure, honest numbers, and transaction states that read like sentences instead of hashes.","md","defiUi",{},true,"\u002Fwriting\u002Fdefi-swap-ui","7 min read",{"title":5,"description":235},"writing\u002Fdefi-swap-ui","39SPouVFVqlRPhDiwakJgllBJGGGGT2iRFMOwowj1yU",1785786127680]