I Built a Free Debt Calculator with Pure HTML/CSS/JS
A few weeks ago I realized something: every debt payoff calculator I found online either required sign-up, looked like it was designed in 2005, or only showed you one strategy at a time.
So I built my own. Zero dependencies. Zero frameworks. Zero backend.
Here's the full walkthrough of how it works under the hood.
The MVP Requirements
I wanted three things:
- Enter debts — name, balance, APR, minimum payment
- Compare both strategies — Snowball (smallest balance first) vs Avalanche (highest APR first) side by side
- See the math — total interest, payoff timeline, monthly schedule
And one non-negotiable: no data leaves your browser. No sign-up, no upload, no server.
The Architecture (It's Just HTML)
index.html
├── <head> → styles + Chart.js CDN
├── <body>
│ ├── Input form (debt table + budget)
│ ├── Strategy toggle (Snowball / Avalanche)
│ ├── Results section
│ │ ├── Summary cards
│ │ ├── Chart.js payoff chart
│ │ ├── Milestone timeline
│ │ └── Payment schedule table
│ └── FAQ section
└── <script> → all JS logic
Single file. Deploy anywhere. Vercel in my case, but Netlify, GitHub Pages, or even a plain web server all work.
The JavaScript: Three Scenarios, One Engine
The core logic runs three scenarios on the same debt data:
function calculateAll(debts, monthlyBudget, strategy) {
// Sort debts by strategy
const sorted = [...debts].sort((a, b) => {
if (strategy === 'snowball') return a.balance - b.balance;
if (strategy === 'avalanche') return b.apr - a.apr;
return 0; // minimum payment only
});
// Run the payoff simulation
return simulatePayoff(sorted, monthlyBudget);
}
The simulatePayoff function runs month by month:
- Calculate interest accrued on each debt
- Apply minimum payments
- Throw remaining budget at the target debt
- When a debt is paid off, roll its payment to the next target
- Record every month (balance, paid status, milestone)
function simulatePayoff(debts, monthlyBudget) {
let month = 0;
const schedule = [];
while (debts.some(d => d.balance > 0) && month < 120) {
month++;
let remaining = monthlyBudget;
// Accrue interest first
debts.forEach(d => {
d.balance += d.balance * (d.apr / 100 / 12);
});
// Find the target debt (first unpaid in sorted order)
const target = debts.find(d => d.balance > 0);
// Apply minimums
debts.forEach(d => {
const min = Math.min(d.minPayment, d.balance);
d.balance -= min;
remaining -= min;
});
// Throw remaining at target
if (target && target.balance > 0 && remaining > 0) {
const extra = Math.min(remaining, target.balance);
target.balance -= extra;
}
schedule.push({ month, debts: debts.map(d => ({ ...d })) });
}
return schedule;
}
The trick: run this three times — once for Minimum Only (no extra payments), once for Snowball, once for Avalanche. Then compare the results side by side.
The Chart: Chart.js with Dynamic Data
I used Chart.js (CDN-loaded) for the payoff timeline:
function renderChart(snowballData, avalancheData) {
const ctx = document.getElementById('payoffChart').getContext('2d');
new Chart(ctx, {
type: 'line',
data: {
labels: snowballData.map(d => `Month ${d.month}`),
datasets: [
{
label: 'Snowball',
data: snowballData.map(d => d.totalRemaining),
borderColor: '#059669',
tension: 0.3
},
{
label: 'Avalanche',
data: avalancheData.map(d => d.totalRemaining),
borderColor: '#2563EB',
tension: 0.3
}
]
},
options: {
responsive: true,
plugins: {
legend: { position: 'top' }
}
}
});
}
Two lines. Same starting point. The visual difference in payoff speed is immediately obvious.
The Result: Snowball vs Avalanche in One View
After running all three scenarios, the user sees:
| Metric | Minimum Only | Snowball | Avalanche |
|---|---|---|---|
| Total Paid | $28,124 | $26,686 | $26,496 |
| Total Interest | $3,424 | $1,986 | $1,796 |
| Payoff Time | 3 yrs 10 mo | 1 yr 11 mo | 1 yr 11 mo |
| Money Saved | — | $1,438 | $1,628 |
Both strategies cut payoff time by half compared to minimum payments.
Key Takeaways for Devs
- You don't need a framework. A single HTML file with vanilla JS can be a full product.
- Client-side calculations are underrated. No server costs, no privacy concerns, no sign-up friction.
- Side-by-side comparison sells itself. Showing the difference is more convincing than telling it.
- Deploy in 2 minutes. Vercel, Netlify, GitHub Pages — pick one, drag your file, done.
The entire project from idea to deployment took about 6 hours. Cost: $0.
Try It or See the Code
🔗 Live tool: https://inisyght.online/debt-calculator
The full source is a single HTML file. View source in your browser — all the logic is right there, commented and readable.
Built with ☕ and a stubborn refusal to sign up for yet another SaaS.
Top comments (0)