Fintech · Banking App · Design System

NovaPay — Design System & Interactive Prototype for Mobile Banking

A banking app I designed on my own, with no client and no brief. I started with the dull part: Figma variables for colour, type and spacing. Then 20+ components, then the screens, then a prototype coded in Next.js and Tailwind so I could check the whole thing held up in a browser rather than in a click-through.

Role
UI/UX Designer & Frontend Developer
Type
End-to-End Product Design
Timeline
Concept to Prototype
Tools
Figma · Next.js · Tailwind CSS · TypeScript
Outcomes
20+
Components with variants and responsive states, drawn once and reused rather than restyled on each screen
41
Screens across mobile and desktop, 22 and 19. Each core flow was drawn at both widths instead of drawn once and stretched
2 modes
Light and dark, both in the tokens from the start, so switching is a toggle rather than a second set of screens
Overview

Banking, redesigned

NovaPay is a fintech banking app I built from nothing, in the order I think it should be built: tokens, components, screens, code. No one was going to hand me a style guide for it, so I made one, and then I made the app to find out whether the style guide was any good.

The tension I kept hitting is that a bank has to look like it can be trusted with your money and also let you check a balance in three seconds. Trust tends to mean density. Speed tends to mean taking things away. Most of what follows is me picking a side, screen by screen.

Design SystemColor tokens · Typography scale · Spacing & radius variables · Component library
Responsive Design22 mobile screens (375px) · 19 desktop screens (1440px) · Adaptive layouts
Component Library20+ reusable Figma components · Variants · Consistent patterns
Interactive PrototypeNext.js · Tailwind CSS · Dark mode · Framer Motion animations
Information ArchitectureUser flows · Screen mapping · Navigation structure · Feature hierarchy
Icon SystemLucide icons · Consistent stroke weight · Semantic iconography
NovaPay — Design System Cover
Design System

Token-based foundations

Everything sits on Figma variables: colour, type, spacing, radius. I did this first because I've done it the other way round and spent the back half of a project hunting hard-coded hex values. It is about an hour of tedious setup. It pays for itself the first time someone asks for a dark mode.

FoundationDetailsPurpose
Colour TokensPrimary, secondary, success, warning, danger palettes with light/dark mode valuesNamed by job, not by hue, so the theme can switch and contrast stays checkable in one place
TypographyInter font family · Display, heading, body, caption scalesIn a banking app the numbers have to outrank their labels. The scale makes that automatic
Spacing4px base unit · 8-point grid · Consistent padding and marginsEvery gap lands on the same grid, so nothing drifts when a layout changes width
Border Radius4px (inputs) · 8px (cards) · 12px (panels) · Full (avatars, badges)Rounded enough to feel current, not so rounded that a bank starts looking like a toy
Components

20+ reusable components

There are 20+ components in the Figma library, all built with variants. The one I redrew most was the transaction row. It has to carry a merchant name, a category, a date and an amount, and at 375px something has to give. I let the merchant name truncate, because that is the part you can usually guess. The amount never does. Every component has default, hover, active and disabled states and works at both breakpoints.

NavigationBottom tab bar (mobile) · Sidebar navigation (desktop) · Breadcrumbs · Back buttons
Data DisplayBalance cards · Transaction rows · Chart components · Stat widgets · Bill cards
Inputs & ActionsButtons (primary, secondary, ghost) · Text inputs · Search · Toggle switches
FeedbackToast notifications · Empty states · Loading skeletons · Success confirmations
Information Architecture

Every screen mapped

ScreenPurposeKey Elements
DashboardFinancial overview at a glanceAvailable balance · Account cards · Upcoming bills · Spending overview chart · Recent transactions
TransactionsComplete transaction historyFilterable list · Category badges · Date grouping · Search · Amount display
TransferSend money between accountsRecipient selection · Amount input · Account picker · Confirmation flow
CardsCard managementVirtual/physical card display · Card details · Freeze/unfreeze · Spending limits
BudgetsSpending category trackingCategory budgets · Progress bars · Monthly comparison · Overspend alerts
Pay BillsBill payment managementUpcoming bills · Payment history · Auto-pay setup · Reminders
AnalyticsFinancial insights & trendsIncome vs spending · Category breakdown · Monthly trends · Savings rate
Profile & SettingsAccount configurationPersonal info · Security settings · Notification preferences · Theme toggle
Request MoneyAsk a contact to pay youContact picker · Amount & note · Sent vs. invited state
RecipientsSaved payees for transfersRecipient list · Verified/unverified badge · Add new recipient
Disputes & SupportFlag and track a disputed transactionReason picker · Evidence upload · Status timeline
ReceiptsProof of a completed transactionItemized breakdown · Share or export · Merchant details

Eight destinations, mapped as a tree

  • NovaPayApp root
    • Onboarding
      Log inSign upForgot passwordOTP verify
    • DashboardBottom tab
    • TransactionsBottom tab
      Disputes & SupportReceipts
    • TransferBottom tab
      Request MoneyRecipients
    • CardsBottom tab
    • BudgetsSidebar · More
    • Pay BillsSidebar · More
    • AnalyticsBottom tab
    • Profile & SettingsSidebar · More

Bottom tab is one of the five icons in the mobile tab bar — Dashboard, Transactions, Transfer, Cards, Analytics. Sidebar · More is the other three: the desktop sidebar has room to list them directly, the 375px build tucks the same three behind a More screen instead. Same eight destinations, two different amounts of space to put them in.

User Flows

Three flows, followed to the edge

The three flows below cover everything that moves money or asks for it to move: sending, requesting, and disputing. Each is drawn as it actually ships, branch points included — how it can end isn't an afterthought bolted on after the happy path.

Send money

Select recipient
Enter amount
Review
Confirm
then, one of three ways:
Completed — funds move immediately
Pending — held for bank processing
Failed — insufficient funds

Confirm is its own screen, restating the recipient and amount, rather than a checkbox on Review — the one step in the app that moves money doesn't share a screen with anything else.

Request money

Choose contact
Amount & note
Send request
then, depending on the contact:
Request sent — notified at once
Invite sent — not on NovaPay yet

No money moves at any point in this flow — only a request does. The note field exists because “Alex requested $40” with no context reads like a mistake to whoever gets it.

Dispute a transaction

Select transaction
Choose a reason
Add evidence
Submit
status becomes Disputed, then resolves one of two ways:
Resolved — refunded
Rejected — reverts to Completed

Disputed sits between Submit and either ending — the transaction shows it honestly, as under review, rather than holding the previous status until someone decides.

Edge Cases & Trust

Designed for what goes wrong

A banking app earns trust in the moments that aren't clean: a transfer still pending, a recipient nobody has verified yet, a card someone froze on purpose. The seven states below are what actually ships; the four cases after them are what the design had to hold up under.

Seven states, one honest signal

CompletedThe default, unremarkable state — no badge at all. A badge appearing anywhere else always means look at this one.
PendingClock icon. Still moving; never shown as if it had already landed.
FailedXCircle icon. The transfer did not happen and the balance did not change.
CancelledSlash icon. Stopped before it settled, by the user or by the system.
ReversedUndo2 icon. Completed, then undone — the ledger keeps both events.
RefundedBanknote icon. Money returned, usually after a dispute closes.
DisputedFlag icon. Flagged by the user, under review, not resolved either way yet.

Pending and Cancelled share a tone; Reversed and Refunded share another. The label and the icon are what actually tell them apart — colour is the last signal here, never the only one.

The edge cases that decide trust

No transactions yetA new account's history screen explains what will show up here, instead of leaving a blank list that reads like the app is broken.Empty state
Unverified recipientA payee added but not yet confirmed carries an amber badge on every screen that lists them, including the send-money picker — not just their own profile.Accurate status
Frozen cardA frozen card stays visible with its real number and limits, greyed out and labelled, rather than disappearing — you froze it, you should still be able to see it.Transparency
Irreversible sendConfirm is its own screen with a re-stated amount and recipient, not a checkbox on the review screen someone could tap through by habit.Confirm before acting
My Process

From concept to prototype

I worked in the order below. It matters more than it looks: tokens before components, components before screens, screens before code. Skip back a step and you end up reconciling two versions of the same card.

Research
Discovery
  • Fintech competitive audit
  • User needs analysis
  • Feature prioritisation
  • Information architecture
Foundation
Design System
  • Color token system
  • Typography scale
  • Spacing & radius variables
  • Figma variable setup
Build
Components
  • 20+ Figma components
  • Variant architecture
  • Responsive behaviour
  • Interaction states
Design
Screens
  • 22 mobile screens (375px)
  • 19 desktop screens (1440px)
  • Dark mode variants
  • User flow diagrams
Code
Prototype
  • Next.js implementation
  • Tailwind CSS styling
  • Framer Motion animations
  • Responsive & dark mode
Design Rationale

Every choice justified

Here are the calls I made and the ones I turned down. This was a self-directed project with no users to test against, so these are reasoned decisions rather than validated ones. I've kept the rejected column because that half is usually more revealing.

DecisionRationaleAlternative Rejected
Dashboard as financial hubMost visits to a banking app last ten seconds: how much is in there, what went out, what's due. Putting those three on one screen means the routine visit needs no navigation at all.A balance-only dashboard. It looks calmer in a portfolio shot and sends you digging for the two things you opened the app for.
Token-based design systemOne edit to a variable updates all 41 screens, and the light and dark values live next to each other instead of in two separate files. A developer reads the numbers off the variables rather than off my redlines.Hard-coded colour values. Fine for five screens. At 41 it turns dark mode into a manual rewrite.
Mobile-first with desktop adaptationPeople bank on their phones. Starting at 375px forced every core flow to survive the tightest space first, and the 1440px versions then spend the extra room on density instead of the phone inheriting a squashed desktop layout.Desktop-first. The mobile version becomes a compression job, with tap targets sized for a cursor.
Dark mode as first-class featurePeople check their balance at 6am and at midnight. Dark mode went into the token system on day one, which is the only cheap time to do it, and it saves battery on OLED screens besides.Light only. Every dark value then has to be invented afterwards, one screen at a time.
Lucide icon systemThe same stroke weight everywhere, and the same set exists as Figma components and as React components. The icon in the mockup is the icon in the build, with nothing redrawn in between.Icons pulled from wherever. Stroke weights stop agreeing, and the tab bar is where you notice it.
Prototype

Interactive walkthrough

This one you can actually use. Move money between accounts, freeze a card, switch the theme. It's built in Next.js with Tailwind and Framer Motion, and building it is the step that catches what a static mockup hides.

Mobile — 14 core screens

Captured from the running build at 390px. Onboarding through settings, every flow proven end to end.

Onboarding
01Onboarding
Log in
02Log in
Home
03Home
Transactions
04Transactions
Transfer
05Transfer
Request money
06Request money
Pay bills
07Pay bills
Cards
08Cards
Budgets
09Budgets
Analytics
10Analytics
Notifications
11Notifications
Profile
12Profile
Settings
13Settings
More
14More

Desktop — the same system at 1440px

One component library, two densities. Nothing is re-drawn for the wider layout; the grid and the nav adapt.

Home
01Home
Transactions
02Transactions
Analytics
03Analytics
Budgets
04Budgets
Transfer
05Transfer
Pay bills
06Pay bills
Request money
07Request money
Notifications
08Notifications
Profile
09Profile
Settings
10Settings
More
11More
Onboarding
12Onboarding
Log in
13Log in
Interactive prototype

The prototype below is the running build — click it to interact.

Technology

From design to code

LayerTechnologyWhy Chosen
DesignFigma (Variables, Components, Auto Layout)Variables are the reason. Nothing else I use handles a token-based design system as directly
FrontendNext.js · TypeScriptOne route per screen, which matched how the Figma file was already organised. TypeScript for the props
StylingTailwind CSSThe spacing and colour utilities map almost one to one onto my tokens, so the code reads like the design file
AnimationFramer MotionPage transitions and chart reveals without hand-writing keyframes for each one
IconsLucide ReactThe same set as the Figma file, so no icon had to be traced or swapped for a near match
Style Guide

Visual foundations

Indigo
#6366F1
Indigo Light
#818CF8
Indigo Dark
#4F46E5
Slate 50
#F8FAFC
Slate 200
#E2E8F0
Slate 500
#64748B
Slate 800
#1E293B
Slate 900
#0F172A
Success
#22C55E
Danger
#EF4444
Warning
#F59E0B
Info
#3B82F6
What I Delivered

What the system covers

Complete design systemColour, type, spacing and radius as variables, plus 20+ components. A developer reads the values straight off the file
Design validated in codeI coded the prototype in Next.js and Tailwind CSS. Every screen and interaction runs in a browser, which is a harder test than a Figma click-through
What this project demonstrates

I did all of it: the tokens, the components, 41 screens, and the code underneath them. The last part is the one I'd point at. Plenty of design systems look consistent in Figma and come apart the moment someone builds them, and the only way I know to find out is to build it yourself. What I can't tell you is how real customers used it. Nobody did. This was self-directed, so it shows the craft, not the outcome.

Next project
Clever Recruit —
High-Density Pipeline for 200+ Candidates
Get in touch

Let’s talk.

Happy to walk through any of these case studies on a call, including the parts that didn’t work.

Please add your name
Please add a valid email
Please add a subject
Please add a message
Open to opportunities
Based inRijeka, Croatia · remote worldwide, or relocating within the EU
Right to workEU citizen (Portugal) · no permit needed anywhere in Europe
Open toUI/UX designer roles, employed or contract
Email me directly atnicole@dinardo.design