A clean, responsive personal finance tracker built with React 18 and Recharts. Track income and expenses, set category budgets, visualize spending trends, and get instant over-budget alerts — all without a backend or external state library.
Live Demo: https://flo-fawn.vercel.app · GitHub: https://github.com/Nebenmor/flo
Dashboard
- Summary cards showing current month income, expenses, savings, and savings rate
- Spending donut chart broken down by category (Housing, Food & Dining, Transport, Entertainment, Health)
- 6-month bar chart comparing income vs. expenses vs. savings over time
- Recent transactions list with quick delete
Transactions
- Add transactions via modal — amount, type (income/expense), category, date, and description
- Full transaction history with search, multi-filter by type/category, and delete
- Real-time updates across all views on every add or delete
Budgets
- Per-category monthly budget limits with animated progress bars
- Live over-budget alerts with visual indicators when spending exceeds set limits
- Inline budget editing — update limits without leaving the page
Responsive Layout
- Sidebar navigation on desktop (768px+)
- Bottom navigation bar on mobile
- CSS Grid
auto-fit/minmaxlayout that adapts charts and cards to any screen size
| Layer | Technology |
|---|---|
| Framework | React 18 |
| Build Tool | Vite 5 |
| Styling | Tailwind CSS 3 |
| Charts | Recharts 2 |
| Icons | Lucide React |
| Persistence | localStorage |
| Deployment | Vercel |
All state lives in a single custom hook — useFinanceData — with no external state management library.
src/
├── components/
│ ├── dashboard/
│ │ ├── SummaryCards.jsx # Income / expenses / savings / rate cards
│ │ ├── SpendingDonut.jsx # Category breakdown donut chart
│ │ ├── MonthlyBarChart.jsx # 6-month income vs expenses bar chart
│ │ └── RecentTransactions.jsx # Latest transactions with delete
│ ├── transactions/
│ │ ├── TransactionList.jsx # Full list with search + filters
│ │ └── AddTransactionModal.jsx # Add transaction modal form
│ ├── budget/
│ │ └── BudgetPanel.jsx # Budget cards with progress bars + alerts
│ └── layout/
│ ├── Sidebar.jsx # Desktop navigation
│ ├── MobileNav.jsx # Mobile bottom navigation
│ └── Header.jsx # Top bar with add transaction button
├── hooks/
│ └── useFinanceData.js # Single source of truth for all finance state
├── constants/
│ └── categories.js # Category definitions (id, label, icon, colors)
├── utils/
│ └── formatters.js # Date and currency formatting helpers
└── data/
└── mockData.js # Seed transactions and budgets for first load
The hook manages all transactions and budgets, derives computed values, and handles localStorage persistence — eliminating the need for Redux, Zustand, or any external state library.
State managed:
transactions— full transaction history (persisted to localStorage)budgets— per-category spending limits (persisted to localStorage)
Derived values computed on every render:
currentMonthTransactions— filtered to the current calendar monthcurrentMonthIncome/currentMonthExpenses/currentMonthSavingssavingsRate— savings as a percentage of incomespendingByCategory— expense totals grouped by category for chartslast6MonthsData— monthly aggregates for the bar chart
Actions exposed:
addTransaction(txn)— prepends with a timestamp-based IDdeleteTransaction(id)— removes by IDupdateBudget(category, limit)— updates a category limit inlineresetToMockData()— restores seed data
Prerequisites: Node.js 18+
# Clone the repository
git clone https://github.com/Nebenmor/flo.git
cd flo/finance-tracker
# Install dependencies
npm install
# Start development server
npm run devOpen http://localhost:5173 in your browser.
# Build for production
npm run build
# Preview production build locally
npm run previewFlo uses a distinctive dark mint design system:
| Token | Value | Usage |
|---|---|---|
| Primary | #14b88a |
Income, positive states, primary actions |
| Danger | #fb7185 |
Expenses, over-budget alerts |
| Background | Dark mesh gradient | App shell |
| Chart colors | Per-category palette | Donut chart segments |
Category colors are defined centrally in src/constants/categories.js and shared across charts, badges, and budget cards for visual consistency.
All data is stored in localStorage under two keys:
flo_transactions— full transaction arrayflo_budgets— category budget limits object
On first load, mock seed data populates both stores so the app is immediately usable without manual data entry. Data survives page refreshes and browser restarts. Clearing browser storage resets the app to seed data on next load.
The app is deployed on Vercel. The vercel.json config handles SPA routing so direct URL access and page refreshes work correctly.
{
"rewrites": [{ "source": "/(.*)", "destination": "/" }]
}To deploy your own instance:
npm install -g vercel
vercel --prodMIT
