TLDR

Baymard Institute, referința internațională pentru UX de checkout, a filmat ani la rând utilizatori reali care cumpără online și a extras din asta sute de reguli. Le-am studiat și le-am aplicat. Dar, în multe locuri, regula îți dă direcția, nu și implementarea. “Pune un modal aici” nu-ți spune cum arată modalul. “Arată detalii de stoc” nu-ți spune câte niveluri sunt. “Profilele salvate trebuie să fie vizibile” nu-ți spune ce faci cu opțiunea “folosește adresa de livrare”, care nu are un profil real în spate. Articolul documentează 7 momente în care golul ăsta a trebuit umplut printr-o decizie. Pentru fiecare: problema, alternativele cântărite, ce am ales și de ce, plus ce am învățat. Iar partea de cod stă separat, în pasaje marcate “pentru devi”, pentru a putea fi sărite.

Golul dintre spec și ce livrezi

Patru forme de adresă duplicate. Un locker picker care arată diferit pe desktop și pe mobil, cu cod paralel care divergează. Un câmp de voucher deschis lângă butonul de plată, care fură atenția majorității celor care n-aveau niciun cod. Astea erau în propriul meu checkout, după ce citisem Baymard săptămâni întregi și făcusem audit pe Stripe, Shopify, eMAG și Altex.

Ghidurile îți spun ce să faci. Că adresa de facturare e, by default, cea de livrare, că input-urile opționale se ascund, că overlay-urile merg pentru sub-task-uri. Nu-ți spun cum. Dacă cele patru forme de adresă sunt un modal sau patru și cum arată modalul ăla, decizi singur. Diferența dintre ce și cum este exact spațiul în care se ia decizia de design.

Primul articol a prezentat 8 ajustări pentru piața din RO. Al doilea: 9 reguli universale ignorate sistematic. Acesta documentează stratul al treilea: deciziile care nu erau dictate nici de Baymard, nici de audit, dar care trebuiau luate. Șapte momente concrete din construirea Otter Checkout v3.

Cum iei o decizie când manualul nu te ajutǎ

Înainte de studii, cum am abordat aceste momente? Procesul contează mai mult decât orice decizie luată individual. Întâi, găsește tensiunea reală. Nu “ce arată cel mai bine”, ci ce forțe se bat aici. Voucher pill contra sertarului deschis nu e despre estetică, ci despre minoritatea cu cod, contra majorității fără cod.

Apoi enumeră opțiunile reale. Cel puțin trei. Cu două faci doar o alegere binară, asta sau asta, și de obicei ratezi a treia cale la care nu te-ai gândit. Cu patru sau cinci începi să inventezi variante pe care nu le-ai construi oricum și nu mai compari decizii reale. Trei te forțează să găsești o a treia variantă reală, fără să aluneci în ipoteze.

Scrie pro și contra concrete. Cu cifre unde le ai. “Inline pe mobil, cu 15 câmpuri, devine un perete de vreo 600 px”, spune ceva. “Inline e mai puțin elegant” nu spune nimic.

Aliniază-te la ceea ce face industria când există un standard și la abținerea documentată când nu. Locker picker e hartă-first, fiindcă Amazon, DPD, Sameday, Glovo și Bolt sunt toate hartă-first. Voucher pill e închis implicit fiindcă Stripe și Shopify fac așa, deși eMAG și Altex fac opusul. Alegi explicit convenția pe care o urmezi, nu din inerție.

La final, documentează. De ce această abordare, ce ai respins. Atât are nevoie următorul om care întreabă “De ce e așa”.

Acum cele 7.

A. Un singur modal pentru patru locuri de editare a adresei

Problema

Aveam patru locuri unde se edita o adresă: “Adaugă adresă nouă” la livrare, “Editează” un card de livrare salvat, “Adaugă adresă de facturare” și „Editează” pe un card de facturare. Patru intrări, patru trasee de cod. Două deschideau un modal, două schimbau un panou inline. Vizual inconsistent, interacțiune inconsistentă, chiar și ordinea tab-urilor fiind inconsistentă. Costul real era pentru mentenanță. Un bug reparat într-un loc nu se repara în celelalte. Auditul a găsit 11 nepotriviri între trasee: focus diferit, alt text de eroare, alt label pe butonul de salvare. Refactorul devenise inevitabil.

Alternativele

Inline peste tot. Toate cele patru, expandate sub cardurile lor. Fără complexitate de modal. Dar facturarea pe persoană juridică are vreo 15 câmpuri (CUI, denumire, județ, localitate, stradă, număr, bloc, plus comutatorul pentru persoană fizică/juridică). Inline pe mobil devine un perete de formular care se bate vizual cu restul checkout-ului. Scrolezi printr-o grămadă de câmpuri fără niciun focus.

Drawer lateral. Un sertar din dreapta pe desktop, bottom-sheet pe mobil. Păstrează contextul secțiunii de dedesubt. Dar pe mobil arată ca un modal pe jumătate de ecran; pe desktop mănâncă jumătate de pagină și cere două animații separate. Plus, pe iOS Safari, sertarele personalizate au figuri cu tastatura deschisă.

Un singur modal, cu tab-uri. Un modal de adresă cu un prop care-i spune ce tip este, tab-uri pentru facturare (fizică și juridică), element nativ pentru focus și ESC. Focus dedicat pe sub-task, slide-up nativ pe mobil, un singur loc de întreținut. Cere mai mult cod la setup, dar centralizat.

Decizia

Am ales modalul unificat. Baymard e direct aici: când schimbarea unei adrese necesită mai multe câmpuri și selectoare, overlay-ul este justificat, fiindcă focalizează atenția pe o singură sarcină. Cele patru intrări devin un singur tipar: deschizi modalul cu tipul potrivit și cu datele inițiale. Câmpurile se schimbă după tip. Livrarea ascunde comutatorul de tab. Facturarea juridică arată tabul cu CUI și butonul de lookup.

Un singur modal pentru toate cele 4 intrări. Tab-urile persoană fizică/juridică schimbă câmpurile, restul rămâne la loc.

❝

Pentru devi. Contract: <AddressFormModal open type initialValue onSave onClose />, pur controlled, părintele ține state-ul. Tab-urile fizică/juridică pe WAI-ARIA strict: role="tablist", aria-selected, tabIndex 0 pe cel selectat și -1 pe rest, navigare cu Arrow keys. <dialog> nativ pentru capcana de focus și ESC gratis. Browser back închide modalul în loc să navigheze (history.pushState la deschidere, listener pe popstate). Logout cât e deschis îl închide. Slide-up pe mobil 200ms, fade plus scale pe desktop 150ms, ambele oprite la prefers-reduced-motion. Net: vreo 320 de linii duplicate eliminate, modalul centralizat la circa 400, cu tot cu ARIA și animație.

Ce am învățat

Modalul e o unealtă de focus, nu un default comod. Pentru o formă cu 8 câmpuri în sus și alegeri alternative (fizică contra juridică), plus câmpuri care se completează singure (CUI aduce alte 4 valori), overlay-ul este justificat. Pentru o formă simplă, nume, email, telefon și inline rămân corecte.

Iar partea de focus nu e opțională. Capcana de focus vine gratis din modalul nativ, dar focusul pe primul câmp la deschidere și întoarcerea focusului pe trigger la închidere cer cod scris de mână. Browser-back-ul care închide modalul e genul de lucru pe care userul nu-l verbalizează niciodată. Îl simte doar când lipsește.

B. Locker picker pe mobil: hartă, chip-uri și un sheet la atingere

Problema

Pe mobil, locker picker-ul avea două frecușuri clare. Rândul de filtre, stivuit pe verticală (județ, căutare localitate, lângă mine, filtre), împinge harta în jos cu vreo 200 px. Și atingerea unui pin te mută într-o vedere de detaliu pe tot ecranul, o schimbare bruscă de context care face imposibilă compararea a două lockere apropiate.

Mai era ceva mai subtil. Pickup-ul (75 de magazine, alegere după brand) primise o lustruire iterativă: căutare sticky, chip-uri, hartă pe tot ecranul, sheet de detaliu. Lockerul (peste 1.000 de puncte, alegere după geografie) rămăsese cu tipare vechi. Cine făcea pick-up și apoi locker în aceeași sesiune simțea diferența. Arătau din generații diferite.

Decizia pentru locker se leagă de ajustarea care a transformat lockerul într-un tile principal, lângă livrare și pick-up (e în primul articol). Dacă locker e cetățean de rang întâi pe ecranul de livrare, pickerul lui nu poate fi de rang doi în implementare.

Alternativele

Pagină separată, /checkout/locker-picker. Pickerul devine o pagină dedicată, în loc de un modal. Browser back merge native. Dar rupe contextul checkout-ului și cere un refactor major al rutării. Și pierde paritatea cu desktopul, unde pickerul rămâne modal cu hartă în două coloane.

Renunță la harta din text; folosește o listă-first cu un buton de hartă. Listă plată sub chipuri: un buton “Vezi pe hartă” deschide harta pe tot ecranul. Paritate vizuală cu pick-up, cod reutilizat. Dar forțezi userul într-o listă de peste 1.000 de rânduri, nenaturală pentru o sarcină de geografie. Și contrazice tot ce face industria. Pickup-ul a mers list-first fiindcă 75 de magazine cu nume cunoscute (ParkLake, AFI, Băneasa) se pot categoriza mental. Lockerele nu sunt.

Chip-uri sus, hartă păstrată, sheet de detaliu la pin. Păstrezi harta și o lustruiești de tot. Un rând de chipuri pe orizontală înlocuiește filtrele stivuite. Căutare sticky care urmărește tastatura. Atingerea unui pin deschide un bottom sheet cu detalii și un buton, în loc să preia întregul ecran. Aliniat cu industria și cu modelul mental “găsește un locker lângă mine”.

Decizia

Am păstrat harta. Trei argumente. Primul, industria: toți competitorii relevanți (Amazon Locker, DPD, Sameday, Glovo, Bolt) folosesc o abordare „hartă-first” pentru punctele de pick-up. Al doilea, sarcina: alegerea unui locker e despre distanță, nu despre brand, iar harta e instrumentul natural pentru a o măsura. Al treilea, plasă de siguranță: lista rămâne ca alternativă pentru cei care preferă scroll și pentru cazul în care geolocația pică sau harta nu se încarcă.

Atingi un pin, se ridică un sheet cu numele lockerului, adresă, brand (easyBox, FANbox), distanță dacă ai geolocație, program și un buton “Alege acest locker”. Atingi alt Pin. Conținutul se schimbă fără a se reîncărca complet. Atingi harta sau tragi sheetul în jos, se închide fără să alegi nimic, modalul rămâne deschis. Apeși butonul, lockerul e ales și te întorci în checkout cu el în listă.

Locker picker pe mobil. Atingi un pin; se afișează un sheet cu detalii, fără să-ți ia tot ecranul.

❝

Pentru devi. Chip-uri sus: județ ca <select> nativ, "lângă mine" pe geolocație, un ? cu legenda pentru brand/tier. Căutarea e sticky cu visualViewport ca să rămână vizibilă când urcă tastatura. Sheetul de detaliu e portat 1:1 din pickup, fără remount la schimbarea pinului. Dismiss pe tap-pe-hartă, X, drag-down peste prag sau Escape. Desktopul (hartă în două coloane) rămâne neschimbat, spațiul de acolo nu cere compromisul de pe mobil.

Ce am învățat

Când userul are două moduri distincte (răsfoiește, contra alege pe hartă), separă-le clar, nu le înghesui în același widget. Pick-up și locker arată similar de la distanță, dar modelul mental diferă fundamental. Pick-up și recunoașterea brandului: 75 de magazine cunoscute. Locker e despre distanță, peste 1.000 de puncte la fel la față. Tipare identice pe suprafață produc frecuș la fiecare pas.

Și sheetul care se ridică la atingere e deja standard pe orice hartă mobilă, de la Airbnb și Uber Eats până la Google Maps. Reinventarea aici produce frecuș. Portarea aliniază muscle memory. Designul mobile-first forțează decizii bune, care pe desktop devin automat “mai mult loc de respirat”.

C. Semnalul de stoc la Click & Collect: 3 niveluri, nu in/out

Problema

În prototipul vechi, fiecare magazin avea un singur câmp: fie toată comanda e în stoc local, fie toată trebuie transferată. Asta nu seamănă cu realitatea unui retail cu multe magazine. Pentru un coș cu 3 produse și un magazin ales, fiecare produs poate fi sau nu în stoc local, în orice combinație: 3 din 3, 2 plus 1 în transfer, 1 plus 2 în transfer sau 0 din 3.

Costul afișării binare: userul vede “În stoc” pe cardul magazinului, alege ridicare azi, primește confirmare, iar a doua zi îl sună un agent: “de fapt, un produs vine din alt magazin, iar ridicarea întârzie cu 2-3 zile”. Telefoane de scuze. Abandon la ridicare în orașele cu transfer dinamic. Plus ceva mai subtil: userul nu poate compara magazinele după cât de repede livrează. Toate arată la fel până când le sună.

Alternativele

Binar, în stoc sau nu. Un boolean per magazin. Zero ambiguitate, cel mai simplu. Dar ascunde ETA-ul real al transferului și cazurile de margine (e în stoc, dar nu la filiala asta). Userul primește un semnal greșit, iar tu pierzi credibilitate la primul apel de scuze. De aici veneam.

“Verifică telefonic”, generic. Un tile uniform care zice “te contactăm pentru confirmare” în toate magazinele. Nicio promisiune falsă, fiindcă nu promite nimic. Dar frecuș maxim și un semnal clar de “n-avem încredere în propriile date”. Userul nu poate sorta sau compara; alege la întâmplare și abandonează când vede că este necesar un telefon pentru fiecare. Onestitate fără utilitate e tot opacitate.

3 niveluri pe produs × magazin, cu sortare automată. Nivel 1, tot coșul în stoc local, ridicare azi cu confirmare. Nivel 2, parțial, partea în stoc plus restul în 2-5 zile. Nivel 3, nimic local, tot în 2-5 zile. Pe fiecare card: o bulină colorată, un cuvânt și un ETA explicit. Lista este sortată după nivel, apoi după distanță. Un filtru “Doar în stoc azi” afișează doar nivelul 1.

Decizia

Am ales 3 niveluri. Numărul ăsta face toată treaba.

Două (in/out) sunt prea bont când realitatea e un gradient. Pierzi exact nivelul 2, cel mai informativ. “2 din 3 azi, 1 în 2-5 zile” e fix ce vrea userul să știe ca să decidă. Cinci niveluri (rar, limitat, disponibil, mult, foarte mult) sunt peste limită. Userul aruncă o privire pe card, nu studiază un tabel și ține minte trei distincții, nu cinci. Trei e punctul dulce pentru incertitudinea de fulfillment, fiindcă se mapează direct pe felul în care gândește omul: sigur, probabil, nu.

Mecanica vizuală: bulină verde, ambră sau portocalie, plus textul (“3 din 3”, “2 din 3”, “0 din 3” la coș cu mai multe produse sau “În stoc” / “În 2-5 zile” la un singur produs), plus un ETA pe nivel. Reasigurarea e neutră la canal (“te anunțăm când e gata”, niciodată “pe email” sau “prin SMS”; canalul rămâne o decizie de backend).

Trei niveluri de stoc în loc de in/out. Bulină, cuvânt și ETA, ca să se citească și fără culori.

❝

Pentru devi. fulfillmentForStore(storeId) întoarce { total, inStock, delayed, tier }, cu tier = inStock === total ? 1 : inStock > 0 ? 2 : 3. Determinism per (produs, magazin) printr-un hash simplu, ca prototipul să arate realist (split 60/40 în stoc local contra transfer). Emoji singur nu ajunge pentru userii cu daltonism, de aia combo-ul bulină plus cuvânt plus ETA e obligatoriu, se citește identic și fără percepția culorii. Sortare: nivel crescător, apoi distanță, dacă pin-ul userului e setat.

Ce am învățat

Două niveluri sunt prea bont când realitatea e un gradient. Forțezi omul să decidă pe baza unui semnal incomplet și plătești cu telefoane de scuze. Cinci e overload. Punctul dulce nu e la granularitate maximă, ci la cel mai mic număr de niveluri care încă acoperă cazurile reale.

Și un ETA explicit bate mereu unul vag. “Ridicare azi după 14:00” contra “în câteva zile” e diferența dintre rezervare și abandon. Specificul clădește încredere chiar și când ETA-ul e prost. Vagul o sapă chiar și când ETA-ul e bun.

D. CUI de la ANAF: completare la ieșirea din câmp, nu buton de căutare

Problema

Persoana juridică, la checkout, trebuie să completeze câteva câmpuri obligatorii: CUI, denumirea firmei, județul, localitatea, precum și adresa sediului. CUI-ul e singurul care nu se poate deduce din altceva. Restul vine determinist din ANAF (API public sau o bază mock pentru prototip). Să tastezi manual 60 de caractere (“Otter Distribution SRL”, “Bd. Unirii nr. 64”, “Sector 3”, “București”) e muncă în plus care n-ar trebui să existe.

Întrebarea de design: cum integrezi lookup-ul? Trei tensiuni. Frecuș: un buton “Caută” cere un click în plus pe drumul fericit. Fallback: ce faci când ANAF pică sau când CUI-ul nu există în registru? Siguranța la editare: după ce datele vin din ANAF, ce împiedică modificarea accidentală a denumirii legale?

Alternativele

Buton “Caută în ANAF”, explicit. Scrii CUI, apeși și datele se completează. Control clar: vezi exact când rulează. Dar e un click în plus pe drumul fericit, iar userul poate uita să-l apese și să tasteze manual restul, irosind toată automatizarea. Baymard recomandă să eviți butoanele de tip “Apply” atunci când nu sunt necesare.

Lookup la tastare, live. La fiecare cifră după a 6-a, declanșezi căutarea. Real-time, zero acțiuni explicite. Dar înseamnă vreo 7 apeluri pe un CUI tastat, rate-limit de la ANAF pe IP-uri partajate și UI care pâlpâie când răspunsurile vin parțial. Plus, semnal greșit: la 7 cifre, firma poate să nu existe; la 8 există, userul vede un “nu am găsit” tranzitoriu și se sperie.

Tăcut, la ieșirea din câmp, cu un fallback blând. Scrii CUI, ieși din câmp (tab sau click altundeva), iar căutarea pornește singură. Câmpurile se completează și se blochează în modul readonly. Dacă ANAF pică sau CUI-ul e invalid, câmpurile rămân editabile manual, fără să oprești fluxul. Un tooltip pe label explică sursa.

Decizia

Am ales varianta tăcută la ieșirea din câmp. Dacă lookup-ul poate porni automat, butonul devine doar un zgomot. Pe drumul fericit (CUI valid, ANAF răspunde), experiența ideală e zero click-uri în plus. Tastezi cifrele; ieși din câmp; restul apare singur.

Fallback-ul manual nu este opțional pentru un serviciu de stat. ANAF, ca orice API guvernamental, are mentenanțe și vârfuri de trafic în perioadele fiscale. Dacă lookup-ul eșuează și nu lași omul să continue manual, blochezi toate comenzile B2B pe durata avariei. Așa că, la eșec, câmpurile devin editabile, userul completează ce știe, comanda pleacă, iar verificarea se face după aceea.

Blocarea readonly după completare previne greșelile. Fără ea, userul poate suprascrie din greșeală “Otter Distribution SRL” adus din ANAF, schimbând astfel denumirea legală. Cu ea, modificarea este posibilă doar prin schimbarea CUI-ului.

Scrii CUI, ieși din câmp, restul vine singur de la ANAF și se blochează. Niciun click în plus.

❝

Pentru devi. State machine cu 4 stări: idle → loading pe blur cu CUI de minim 6 cifre; loading → ok pe 200 cu match, auto-fill pe denumire, adresă, oraș, județ, plus readOnly pe cele 4; loading → err pe 404, timeout sau network fail, câmpurile rămân editabile cu mesaj inline; ok/err → idle când CUI-ul se schimbă, re-trigger pe următorul blur. Tooltip pe label pentru sursă. În prototip lookup-ul e ~600ms (mock), sub 1.5s pe API-ul real.

Ce am învățat

Automatizarea tăcută bate butonul explicit când datele sunt deterministe și sursa este un API public. Butoanele de “Apply” sunt corecte când acțiunea este ambiguă (aplică un cupon, vezi studiul F) sau reversibilă (aplică un filtru). Nu sunt necesare când acțiunea este o funcție matematică; rezolvă un CUI din denumire, plus o adresă.

State machine-ul cu patru stări (idle, loading, ok, err) e exact cât trebuie. Mai puține și ratezi încărcarea sau întâmpini o eroare. Mai multe (debounce, partial-ok, stale-ok, retrying) sunt overengineering pentru un singur apel.

E. Profile de facturare: “adresa de livrare” ca primul card din listă

Problema

Pentru un user logat, cu profile salvate, secțiunea de facturare are 3 intenții posibile. Folosește datele de livrare pentru facturare (în majoritatea cazurilor). Alege un profil salvat (Otter Distribution SRL). Adaugă un profil nou.

Tiparul vechi amestecă două UI-uri concurente. Un toggle “Folosește datele de la livrare” sus, plus o listă de profile dedesubt. Toggle ON, listă ascunsă. Toggle OFF, listă vizibilă. Două niveluri de selecție pentru aceeași întrebare: “cu ce facturare pleacă comanda?”. Userul trebuia să facă două operații mentale ca să răspundă la una. Vede toggle-ul ON și uită că există profile salvate. Vede toggle-ul OFF și uită că poate folosi datele de livrare fără să creeze un profil.

Alternativele

Checkbox “Folosește datele de la livrare”, sus. Tiparul moștenit, prebifat. Simplu și familiar pentru cei care comandă pentru prima dată. Dar invizibil pentru userul cu profiluri salvate, care nu deschide niciodată secțiunea. Și creează două sisteme pentru aceeași intenție: e ori checkbox, ori profil, niciodată amândouă la vedere.

Toggle ascuns sub "Adaugă profil nou". Ascunzi opțiunea “folosește livrarea” sub un link discret în listă. UI minim, listă curată. Dar opțiunea cea mai populară ajunge să fie cea mai ascunsă. Penalizezi cazul majoritar de dragul eleganței.

Un card virtual “DELIVERY”, preselectat în partea de sus a listei. Apare ca primul card din lista de profile, cu eticheta “Același cu adresa de livrare” și adresa de dedesubt. Preselectat. Utilizatorul îl alege ca pe orice alt profil. Modelul mental se unifică: toate facturările sunt “profile”, iar cazul majoritar e vizibil fără frecuș. Costul: e virtual; nu e un profil real în baza de date, deci necesită o tratare specială în cod.

Decizia

Am ales cardul virtual. Apare doar pentru userii logați și doar când livrarea nu e la locker (lockerul n-are o adresă de oglindit). Fără buton “Editează” pe el, fiindcă datele lui trăiesc în secțiunea de livrare, deci a-l edita înseamnă a edita acolo. La colaps, sumarul arată “Factură pe adresa de livrare” sau “Factură pe profil, {firma}, CUI {x}”.

De ce bate varianta cu toggle plus listă: modelul mental e coerent. Userul gândește „alege o facturare”, iar UI-ul răspunde cu o listă în care toate opțiunile sunt carduri. Cardul “livrare” e doar primul. Baymard cere și ca facturarea să fie, by default, cea de livrare și ca profilele salvate să fie proeminente. Două reguli care converg pe aceeași zonă cer o singură suprafață, nu două care se completează doar pe jumătate.

Cardul “Același cu adresa de livrare” e primul din listă, nu un toggle separat.

❝

Pentru devi. Cardul e sintetizat din selectedAddress (adresa de livrare aleasă), nu din savedBilling. Selectarea lui setează billingSameAsDelivery = true și golește selectedBillingId. La hidratare, facturarea citește din selectedAddress în loc de savedBilling.find(...). Asta e singura buclă specială. Restul UI-ului tratează cardul "livrare" ca pe oricare altul. Mai puține linii speciale decât duplicatul de UI (toggle plus listă).

Ce am învățat

Când o opțiune e recomandarea implicită (folosește livrarea ca facturare, cazul majoritar la userii logați), pune-o explicit ca primul card din listă, n-o ascunde sub un toggle. Toggle-ul comprimă opțiunea într-un bit. Cardul îi dă vizibilitate egală cu cea a celorlalți.

Un “record” virtual, cu tratare specială în cod, e un cost acceptabil pentru consistența din UI. Buclele care sintetizează cardul din altă sursă sunt mai puține decât duplicatul de interfață, iar userul nu vede niciodată complexitatea din spatele acestuia. “Facturarea e o selecție de profil” se internalizează mai ușor decât “facturarea e un checkbox sau o listă; depinde de un toggle”.

F. Voucher pill: cât de vizibil faci câmpul de cupon

Problema

Userii caută activ codul promo înainte de checkout. “otter voucher” este un termen real pe Google. Câmpul de voucher trebuie să existe. Întrebarea e cum îl arăți fără să sabotezi userii care n-au cod.

Două forțe în tensiune. Cei cu cod vor să-l aplice imediat, orice frecuș li se pare obstacol. Cei fără cod, când văd un câmp deschis lângă buton, simt că le scapă ceva: lasă checkout-ul, deschid Google, caută “OTTER cod promo”, se întorc dezamăgiți sau nu se mai întorc. Un câmp deschis fără cod este o taxă pe rata de finalizare. Iar la majoritatea checkout-urilor, fracția care chiar aplică un voucher e mică față de total. Câmpul mereu vizibil servește acea minoritate, dar costă atenția majorității.

Alternativele

Sertar deschis, câmp mare lângă buton. Tiparul eMAG, Altex și multe site-uri din RO. Zero frecuș pentru cei cu cod. Dar cei fără cod simt că ratează ceva și pleacă pe Google, iar câmpul fură spațiu chiar lângă CTA și slăbește ierarhia (“care e acțiunea principală, aplic cod sau plătesc?”). Penalizezi majoritatea pentru minoritate.

Modal de voucher. Un buton deschide un dialog cu câmp și opțiunile „Aplică”/„Renunță”. Focus separat, zero clutter pe checkout. Dar e overkill pentru un singur câmp și rupe fluxul (focus trap, escape, scroll lock). Modalul se rezervă pentru subtask-uri reale (locker picker, adăugare adresă). Un text input nu cere modal.

Pill închis, implicit, cu expand inline. Un buton mic, “Ai un cod de voucher?”, cu o iconiță de etichetă. Click și se deschide câmpul „Plus”, „Aplică” și „Renunță”, fix pe locul pill-ului. Zero distragere pentru cei fără cod, un click în plus pentru cei cu cod. CTA-ul rămâne singura acțiune vizibilă. Tiparul Stripe și Shopify default.

Decizia

Am ales pill-ul închis, default, deasupra butonului de plată. Cod valid produce un chip cu sumă (“OTTER10 aplicat, 10%, -36 lei”) și un buton de clear. Cod invalid produce un mesaj inline (“Codul nu e valid sau a expirat”); câmpul rămâne editabil; Enter aplică.

De ce bate sertarul și modulul: vizibilitatea intrării nu e același lucru cu vizibilitatea câmpului. Pill-ul este accesibil (iconiță plus “Ai un cod de voucher?”). Câmpul nu trebuie să fie deschis ca să existe. Baymard cere ca input-urile opționale, pe care majoritatea nu le folosesc, să fie ascunse de default, tocmai ca să nu declanșezi coupon-hunting și abandon. Costul real: un click în plus pentru cel cu cod. Pentru cel fără: zero click-uri, zero distragere.

Voucherul stă închis ca pill. Un click îl deschide. Cine n-are cod nu-l vede deloc.

❝

Pentru devi. Voucher block cu 3 stări: chip cu clear (cod aplicat), câmp expandat cu Aplică plus Renunță (deschis), sau pill (default). Input cu autoComplete="off", handler pe Enter care previne submit-ul formei, autoFocus doar pe (hover: hover), ca să nu deschidă tastatura pe mobil la o atingere accidentală. Pe mobil pill-ul stă deasupra CTA, pe desktop lângă el.

Ce am învățat

Input-urile opționale pe care majoritatea nu le folosesc se ascund default. Nu “mai puțin vizibile”, ci ascunse. Pill-ul exprimă posibilitatea fără să afișeze câmpul, iar această distincție pune toată greutatea.

Un click în plus pentru minoritatea cu cod e un cost acceptabil pentru zero frecuș la majoritate. Calculul nu e per-user-egal, e ponderat pe distribuția reală. Sertarul deschis al eMAG și Altex servește o minoritate vizibilă, dar costă atenția majorității și s-a perpetuat prin copiere între site-uri, nu prin testare. Stripe, Shopify și Dossier converg pe pill. Outlierii păstrează tiparul din inerție.

H. Register: “product, not brand”, culorile inversate pe checkout

Problema

Otter, ca brand, are o paletă vie: roșu, gradient roșu spre portocaliu, galben accent. Pe pagina de produs, culorile astea sunt dominante și e bine așa, fiindcă acolo userul e în mod “seducție”. Navighează, scanează, decide. Energia de brand produce engagement.

La checkout, același tratament are efect invers. Userul a decis deja: e în mod “finalizez în siguranță”. Roșul peste tot îl pune să facă diferența între “vibe de brand” și “atenție necesară”, o muncă mentală care n-ar trebui să existe. Și mai grav: când apare în sfârșit butonul de plată, acțiunea cu consecință financiară, cum mai semnalezi “atenție”, dacă toată suprafața e deja roșie?

Alternativele

Roșu de brand peste tot, ca pe pagina produsului. Header roșu, gradient pe suprafață, butoane roșii. Identitate de brand 100%, recunoaștere instantă. Dar userul, în mod “finalizez”, trebuie să ignore energia de brand ca să se concentreze. Nu mai distingi “vibe” de “acțiune necesară”, iar butonul de plată nu mai are unde să strălucească, fiindcă suprafața e deja roșie.

Roșu doar pe CTA, restul neutru. Reduci brandul la ultimul punct. CTA-ul final e clar diferit. Dar roșul rămâne semnalul principal pe checkout, iar asta îl slăbește în momentul plății. Și nu rezolvă cum semnalezi stările pozitive intermediare (email valid, secțiune completă). Cu roșu? Atunci CTA-ul nu mai e diferit. Cu ceva neutru? Atunci n-ai niciun semnal pozitiv pentru user.

Inversezi semnificația culorilor: verde sigur, roșu atenție. Verdele devine semnalul de “ești OK”, de completare: email valid, telefon valid, secțiune gata, “ai deblocat transport gratuit”, “în stoc”. Roșul Otter rămâne rar și prețios. Apare doar pe CTA-ul final (când forma e validă), pe erorile majore și pe prețurile tăiate. Neutrele (crem, gri, cerneală) țin corpul: câmpuri, text, separatoare.

Decizia

Am ales inversiunea. Definiția registrului din spec-ul de design: “product, not brand”. Designul servește sarcina userului. Identitatea Otter a fost deja integrată în pagina produsului. Checkout-ul este o schimbare de mod, spre o completare concentrată. Reținere intenționată, nu absența brandului.

Iar plata e răsplata vizuală. Cât timp forma e incompletă, butonul e gri. Când toate secțiunile sunt gata, trece la gradientul roșu-portocaliu. Momentul ăla e câștigat tocmai fiindcă restul e reținut. E regula peak-end: userul reține că experiența s-a încheiat cu un semnal pozitiv puternic, nu că suprafața a fost roșie peste tot și că butonul s-a topit în fundal.

Butonul rămâne gri până când formularul e gata, apoi devine cu gradient. Momentul ăsta e câștigat, fiindcă restul e reținut.

❝

Pentru devi. Trei roluri de culoare. Succes/safe: verde (--success), pe completarea secțiunilor, "email valid", "ai deblocat transport gratuit", shield-check pe nota de stoc. Acțiune/plecare: roșul de brand (--otter-red, gradient), pe CTA bloom (doar când forma e validă), prețuri tăiate, erori. Neutru: cerneală plus cream plus gri, pe câmpuri, text, separatoare. Reținere și pe elevation, nu doar pe culoare: corpul stă pe nivelele 0-1, modalele și tooltipurile la 3-4 sunt rare.

Ce am învățat

Designul e dependent de context. Consistența de brand între pagini nu este obligatorie atunci când registrul produsului diferă. Pagina de produs e mod-brand (engage). Checkout-ul e mod produs (finalizează). Tratamentul ideal pentru fiecare este diferit, nu identic.

Inversiunea (verde: sigur, roșu: atenție) nu e o ciudățenie în RO. Stripe Checkout, eMAG după redesignul recent și Shopify default converg toate către ea. Recunoașterea brandului stă pe logo, pe tipografie, pe garanție și pe semnalele de încredere, nu pe culoarea dominantă a suprafeței. “Reținere intenționată, nu absența brandului” e fraza-cheie: rezervă brandul pentru momentele în care îmbunătățește experiența (plata care strălucește, atenția acordată erorilor, prețul tăiat), nu pentru momentele în care concurează cu sarcina.

Ce împart cele 7 decizii

Le pui una lângă alta și sare în ochi o trăsătură comună: Baymard a dat direcția, nu și implementarea. “Pune overlay pentru forme mari” nu-ți spune că un singur modal cu un prop bate patru modale separate. “Ascunde input-urile opționale” nu-ți spune dacă voucherul e un pill, un link discret sau un dropdown. “Facturarea egală cu livrarea” nu-ți spune dacă o faci ca toggle sau ca primul card din listă. Iar semnalul de stoc pe 3 niveluri și inversiunea culorilor nu sunt nici măcar reguli ale Baymard.

Trei principii merită menționate explicit.

Alternative explicite înainte de decizie. Nu sări direct la soluția care-ți place. Enumeră 2-3 abordări reale, scrie pro și contra concrete, alege motivat. Procesul ăsta a oprit reflexe de tip “modal ca primă idee” sau “sertar de voucher deschis implicit”, pe care le-aș fi folosit automat dacă mergeam direct la implementare.

Costul asimetric este o alegere de design validă. Voucherul cere un click în plus pentru minoritatea cu cod, dar zero distragere pentru majoritatea. Plata care strălucește cere reținere peste tot, dar produce un efect puternic la final. Modalul unificat cere mai mult cod la setup, dar șterge 320 de linii duplicate și 11 nepotriviri. Calculul este ponderat pe distribuția reală și pe costul de mentenanță, nu pe user sau pe linie de cod.

Aliniere la industrie când există, abatere documentată când nu. Locker picker e hartă-first fiindcă Amazon, DPD, Sameday, Glovo, Bolt sunt așa. Voucher pill e închis default fiindcă Stripe, Shopify, Dossier sunt așa. Inversiunea de culori urmează modelul Stripe, eMAG și Shopify. Când urmezi convenția sedimentată, plătești zero în muscle memory. Când te abați, abaterea trebuie notată și justificată.

Un lucru, ca să fim cinstiți. Niciuna dintre cele șapte nu este validată cu A/B pe trafic mare. Sunt decizii raționate, nu victorii dovedite în cifre, iar într-un magazin mare o singură schimbare de-asta rar mișcă rata de conversie. Valoarea lor e alta: elimini frecuș pe care nu trebuia să-l ai, ieftin, și lași în urmă un cod pe care următorul om îl poate citi. Restul, dacă mută acul, se vede în timp, nu într-un singur test.

Peste două săptămâni, ultimul din serie: uneltele care au făcut posibilă toată povestea. Un checklist concret de audit pentru piața din RO. Cod gata de copiat pentru tiparele-cheie. Design tokens pentru registrul “product, not brand”. Plus template-urile pe care le folosim acum, sistematic, pentru spec-uri și planuri. La final, cele 4 articole sunt strânse într-un PDF, cu cross-references și anexă de audit.

Pe data viitoare.