Build a Retirement Calculator 🏖️
Retirement planning is the ultimate "Long-Term" calculation. It involves two distinct phases:
- Accumulation: Saving money while working (Compound Growth).
- Withdrawal: Spending money while retired (Decumulation).
In this guide, we will build a calculator that answers the #1 question: "How much do I need to save monthly to retire by X?"
Step 1: The "Magic Number" (Nest Egg) 🥚
First, we need to know how much total money is needed.
A common rule of thumb is the 4% Rule (or 25x Rule).
If you need $50,000/year in retirement, you need $50,000 / 0.04 = $1,250,000.
The Formula:
Target = Annual_Spending / Withdrawal_Rate
Step 2: The Monthly Contribution 💰
Once we have the Target ($1.25M), we calculate how much to save monthly to hit it, given an interest rate. This is the PMT (Payment) formula for Future Value.
PMT = Target * (r / ((1 + r)^n - 1))
Where:
r: Monthly Interest Rate (Annual / 12)n: Total Months (Years to Retire * 12)
Step 3: The Full React Component 💻
Here is a calculator that connects these two dots.
"use client"
import { useState } from "react"
import { Calculator, Target, TrendingUp } from "lucide-react"
export default function RetirementCalc() {
const [currentAge, setCurrentAge] = useState(30)
const [retireAge, setRetireAge] = useState(65)
const [currentSavings, setSavings] = useState(50000)
const [annualSpend, setSpend] = useState(60000)
const [roi, setRoi] = useState(7) // Return on Investment
const calculate = () => {
// 1. Calculate Magic Number (25x Rule)
const nestEggNeeded = annualSpend * 25
// 2. Calculate Growth of Current Savings
const years = retireAge - currentAge
const r = roi / 100 / 12
const n = years * 12
// Future Value of Current Savings: P * (1+r)^n
const fvCurrent = currentSavings * Math.pow(1 + r, n)
// 3. Gap to Cover
const gap = nestEggNeeded - fvCurrent
// 4. Monthly Contribution Needed: PMT Formula
// If gap is negative, you're already set!
if (gap <= 0) return { nestEgg: nestEggNeeded, monthly: 0 }
const monthlyNeeded = gap * (r / (Math.pow(1 + r, n) - 1))
return { nestEgg: nestEggNeeded, monthly: monthlyNeeded }
}
const { nestEgg, monthly } = calculate()
return (
<div className="max-w-xl mx-auto p-6 bg-white border rounded-xl shadow-lg">
<div className="flex items-center gap-3 mb-6 pb-4 border-b">
<div className="bg-green-100 p-2 rounded-lg text-green-700">
<Calculator size={24} />
</div>
<h2 className="text-xl font-bold text-slate-800">Retirement Planner</h2>
</div>
<div className="space-y-4">
<div className="grid grid-cols-2 gap-4">
<div>
<label className="text-xs font-bold uppercase text-slate-500">Current Age</label>
<input
type="number" value={currentAge} onChange={e => setCurrentAge(Number(e.target.value))}
className="w-full p-2 border rounded font-mono mt-1"
/>
</div>
<div>
<label className="text-xs font-bold uppercase text-slate-500">Retire Age</label>
<input
type="number" value={retireAge} onChange={e => setRetireAge(Number(e.target.value))}
className="w-full p-2 border rounded font-mono mt-1"
/>
</div>
</div>
<div>
<label className="text-xs font-bold uppercase text-slate-500">Current Savings ($)</label>
<input
type="number" value={currentSavings} onChange={e => setSavings(Number(e.target.value))}
className="w-full p-2 border rounded font-mono mt-1"
/>
</div>
<div>
<label className="text-xs font-bold uppercase text-slate-500">Desired Annual Income in Retirement ($)</label>
<input
type="number" value={annualSpend} onChange={e => setSpend(Number(e.target.value))}
className="w-full p-2 border rounded font-mono mt-1"
/>
<p className="text-xs text-slate-400 mt-1">Based on 4% Withdrawal Rule</p>
</div>
<div>
<label className="text-xs font-bold uppercase text-slate-500">Expected Annual Return (%)</label>
<input
type="number" value={roi} onChange={e => setRoi(Number(e.target.value))}
className="w-full p-2 border rounded font-mono mt-1"
/>
</div>
</div>
{/* RESULTS BOX */}
<div className="mt-8 bg-slate-900 text-white p-6 rounded-xl shadow-xl">
<div className="flex items-center gap-2 mb-4 text-slate-400 text-sm font-bold uppercase tracking-wider">
<Target size={16} /> Result
</div>
<div className="grid grid-cols-2 gap-8">
<div>
<div className="text-sm text-slate-400 mb-1">Total Nest Egg Needed</div>
<div className="text-2xl font-bold text-green-400">
${nestEgg.toLocaleString()}
</div>
</div>
<div>
<div className="text-sm text-slate-400 mb-1">Monthly Savings Needed</div>
<div className="text-2xl font-bold text-white">
${monthly.toLocaleString(undefined, {maximumFractionDigits: 0})}
</div>
</div>
</div>
<div className="mt-6 pt-4 border-t border-slate-800 text-xs text-slate-500">
<TrendingUp size={12} className="inline mr-1" />
This assumes a {roi}% annual return compounded monthly. Safe withdrawal rate of 4%.
</div>
</div>
</div>
)
}
Step 4: Adding Inflation (Advanced) 🎈
The calculator above uses "Nominal Dollars". To make it "Real" (Inflation Adjusted), users should input a "Real Return Rate".
- Generic Market Return: 10%
- Inflation: 3%
- Real Return: 7%
Simply advising users to input "7%" instead of "10%" allows your simple calculator to handle inflation without complex code!