Auto Loan Calculator
body {
background: #f7f7f7;
font-family: 'Segoe UI', Arial, sans-serif;
margin: 0;
color: #222;
}
h1 {
font-size: 2.2rem;
text-align: center;
margin-top: 32px;
margin-bottom: 18px;
font-weight: 400;
}
.calc-container {
background: #fff;
max-width: 900px;
margin: 0 auto 30px auto;
border-radius: 10px;
box-shadow: 0 2px 12px rgba(0,0,0,0.08);
padding: 24px 24px 12px 24px;
}
.form-row {
display: flex;
flex-wrap: wrap;
gap: 18px 24px;
margin-bottom: 18px;
justify-content: space-between;
}
.form-group {
flex: 1 1 180px;
min-width: 180px;
}
.form-group label {
display: block;
font-size: 1rem;
margin-bottom: 5px;
font-weight: 500;
}
.form-group input[type="number"], .form-group input[type="date"] {
width: 100%;
padding: 7px 10px;
font-size: 1rem;
border: 1.5px solid #c4c4c4;
border-radius: 5px;
background: #f8f8f8;
transition: border-color 0.2s;
}
.form-group input[type="number"]:focus, .form-group input[type="date"]:focus {
border-color: #007bff;
outline: none;
}
.form-group.inline {
display: flex;
align-items: center;
}
.form-group.inline label {
margin-right: 6px;
margin-bottom: 0;
}
.form-group.inline input {
width: 60px;
margin-right: 6px;
}
.form-actions {
display: flex;
align-items: flex-end;
justify-content: flex-end;
}
.form-actions button {
padding: 10px 32px;
background: #1976d2;
color: #fff;
font-size: 1.1rem;
font-weight: 600;
border: none;
border-radius: 5px;
cursor: pointer;
margin-top: 10px;
transition: background 0.2s;
}
.form-actions button:hover {
background: #1259a7;
}
.summary-row {
display: flex;
justify-content: space-between;
align-items: flex-end;
margin: 22px 0 10px 0;
flex-wrap: wrap;
gap: 18px 0;
}
.monthly-payment {
width: 100%;
text-align: center;
font-size: 2rem;
font-weight: 600;
color: #1976d2;
margin-bottom: 2px;
}
.summary-boxes {
display: flex;
justify-content: space-between;
gap: 10px;
width: 100%;
margin: 0 auto;
flex-wrap: wrap;
}
.summary-box {
flex: 1 1 160px;
background: #f3f7fb;
border-radius: 7px;
padding: 12px 10px 8px 10px;
text-align: center;
margin: 0 2px;
min-width: 130px;
}
.summary-box .label {
font-size: 0.98rem;
color: #888;
margin-bottom: 2px;
display: block;
}
.summary-box .value {
font-size: 1.1rem;
font-weight: 600;
color: #222;
}
.chart-section {
background: #fff;
border-radius: 10px;
margin: 18px auto 0 auto;
padding: 20px 14px 10px 14px;
max-width: 900px;
box-shadow: 0 2px 8px rgba(0,0,0,0.06);
}
.tabs {
display: flex;
margin-bottom: 0;
border-bottom: 2px solid #e3e3e3;
margin-top: 18px;
}
.tab-btn {
padding: 10px 22px;
background: #e3e3e3;
border: none;
border-radius: 7px 7px 0 0;
font-weight: 500;
font-size: 1.02rem;
cursor: pointer;
margin-right: 6px;
transition: background 0.2s;
}
.tab-btn.active {
background: #1976d2;
color: #fff;
}
.amort-table {
width: 100%;
border-collapse: collapse;
margin-top: 0;
font-size: 0.98rem;
background: #fff;
}
.amort-table th, .amort-table td {
border: 1px solid #e3e3e3;
padding: 7px 10px;
text-align: right;
}
.amort-table th {
background: #f3f7fb;
color: #1976d2;
font-weight: 600;
}
.amort-table td:first-child, .amort-table th:first-child {
text-align: left;
}
.amort-table tfoot td {
font-weight: bold;
background: #f8f8f8;
color: #1976d2;
}
@media (max-width: 900px) {
.calc-container, .chart-section {
max-width: 98vw;
padding: 10px 2vw 10px 2vw;
}
.summary-row, .summary-boxes {
flex-direction: column;
align-items: stretch;
}
.summary-box {
margin-bottom: 8px;
}
}
Auto Loan Calculator
Loan Amount
Over Payments
Total Interest
Pay-off Date
Amortization Schedule
Yearly Amortization
Monthly Amortization
function formatCurrency(n) {
return n.toLocaleString('en-US', {style: 'currency', currency: 'USD', minimumFractionDigits: 2});
}
function formatDate(date) {
return date.toLocaleDateString('en-US', {year: 'numeric', month: 'short'});
}
function formatFullDate(date) {
return date.toLocaleDateString('en-US', {year: 'numeric', month: 'short', day: '2-digit'});
}
function getPayoffDate(startDate, months) {
let d = new Date(startDate);
d.setMonth(d.getMonth() + months - 1);
return formatDate(d);
}
function getPayoffFullDate(startDate, months) {
let d = new Date(startDate);
d.setMonth(d.getMonth() + months - 1);
return formatFullDate(d);
}
function calcLoanAmount(vehiclePrice, downPayment, tradeIn, owedOnTrade, salesTax) {
// Loan Amount = (Vehicle Price - Down Payment - Trade-In + Owed on Trade) * (1 + Sales Tax Rate)
let base = vehiclePrice - downPayment - tradeIn + owedOnTrade;
let tax = base * (salesTax / 100);
return base + tax;
}
function calcMonthlyPayment(P, annualRate, n) {
let r = annualRate / 100 / 12;
if (r === 0) return P / n;
return P * r / (1 - Math.pow(1 + r, -n));
}
function buildAmortization(P, annualRate, n, startDate) {
let r = annualRate / 100 / 12;
let payment = calcMonthlyPayment(P, annualRate, n);
let schedule = [];
let balance = P;
let date = new Date(startDate);
for (let i = 1; i <= n; i++) {
let interest = balance * r;
let principal = payment - interest;
if (balance < principal) principal = balance;
balance -= principal;
if (balance {
let y = row.date.getFullYear();
if (!years[y]) years[y] = {principal: 0, interest: 0, payment: 0, balance: row.balance, lastDate: row.date};
years[y].principal += row.principal;
years[y].interest += row.interest;
years[y].payment += row.payment;
years[y].balance = row.balance;
years[y].lastDate = row.date;
});
let result = [];
let i = 1;
for (let y in years) {
result.push({
year: y,
principal: years[y].principal,
interest: years[y].interest,
totalPaid: years[y].payment,
balance: years[y].balance,
lastDate: years[y].lastDate
});
i++;
}
return result;
}
function renderTable(schedule, type) {
let html = '
';
if (type === 'year') {
html += `
Year Principal Interest Total Paid Balance `;
let totalPrincipal = 0, totalInterest = 0, totalPaid = 0;
schedule.forEach(row => {
totalPrincipal += row.principal;
totalInterest += row.interest;
totalPaid += row.totalPaid;
html += `
${row.year}
${formatCurrency(row.principal)}
${formatCurrency(row.interest)}
${formatCurrency(row.totalPaid)}
${formatCurrency(row.balance)}
`;
});
html += `
Totals
${formatCurrency(totalPrincipal)}
${formatCurrency(totalInterest)}
${formatCurrency(totalPaid)}
`;
} else {
html += `
# Date Principal Interest Payment Balance `;
let totalPrincipal = 0, totalInterest = 0, totalPaid = 0;
schedule.forEach(row => {
totalPrincipal += row.principal;
totalInterest += row.interest;
totalPaid += row.payment;
html += `
${row.paymentNum}
${formatFullDate(row.date)}
${formatCurrency(row.principal)}
${formatCurrency(row.interest)}
${formatCurrency(row.payment)}
${formatCurrency(row.balance)}
`;
});
html += `
Totals
${formatCurrency(totalPrincipal)}
${formatCurrency(totalInterest)}
${formatCurrency(totalPaid)}
`;
}
html += '
';
document.getElementById('amortTableWrap').innerHTML = html;
}
// Chart
let loanChart;
function renderChart(yearly) {
let ctx = document.getElementById('loanChart').getContext('2d');
let labels = yearly.map(row => row.year);
let principalData = yearly.map(row => row.principal);
let interestData = yearly.map(row => row.interest);
let balanceData = yearly.map(row => row.balance);
if (loanChart) loanChart.destroy();
loanChart = new Chart(ctx, {
type: 'bar',
data: {
labels: labels,
datasets: [
{
label: 'Principal',
type: 'bar',
data: principalData,
backgroundColor: '#1976d2',
stack: 'stack1'
// ...bar options
},
{
label: 'Interest',
type: 'bar',
data: interestData,
backgroundColor: '#ff9800',
stack: 'stack1'
// ...bar options
},
{
label: 'End Balance',
data: balanceData,
backgroundColor: '#bdbdbd',
type: 'line',
borderColor: '#222',
borderWidth: 2,
fill: false,
pointRadius: 4,
yAxisID: 'y1'
// ...line options
}
]
},
options: {
plugins: {
legend: {display: true, position: 'top'},
tooltip: {mode: 'index', intersect: false}
},
responsive: true,
scales: {
x: {stacked: true},
y: {
stacked: true,
title: {display: true, text: 'Amount ($)'},
beginAtZero: true
},
y1: {
position: 'right',
grid: {drawOnChartArea: false},
title: {display: true, text: 'Balance ($)'},
beginAtZero: true
}
}
}
});
}
// Main calculation
function calcAndRender() {
let vehiclePrice = parseFloat(document.getElementById('vehiclePrice').value) || 0;
let downPayment = parseFloat(document.getElementById('downPayment').value) || 0;
let tradeIn = parseFloat(document.getElementById('tradeIn').value) || 0;
let owedOnTrade = parseFloat(document.getElementById('owedOnTrade').value) || 0;
let interestRate = parseFloat(document.getElementById('interestRate').value) || 0;
let salesTax = parseFloat(document.getElementById('salesTax').value) || 0;
let term = parseInt(document.getElementById('term').value) || 1;
let startDate = document.getElementById('startDate').value;
if (!startDate) startDate = new Date().toISOString().slice(0,10);
let loanAmount = calcLoanAmount(vehiclePrice, downPayment, tradeIn, owedOnTrade, salesTax);
let monthlyPayment = calcMonthlyPayment(loanAmount, interestRate, term);
let totalPaid = monthlyPayment * term;
let totalInterest = totalPaid - loanAmount;
let payoffDate = getPayoffDate(startDate, term);
document.getElementById('monthlyPayment').innerHTML = formatCurrency(monthlyPayment) + '
Monthly Payment
';
document.getElementById('loanAmountBox').textContent = formatCurrency(loanAmount);
document.getElementById('totalPaymentsBox').textContent = term;
document.getElementById('totalPaidBox').textContent = formatCurrency(totalPaid);
document.getElementById('totalInterestBox').textContent = formatCurrency(totalInterest);
document.getElementById('payoffDateBox').textContent = payoffDate;
let schedule = buildAmortization(loanAmount, interestRate, term, startDate);
let yearly = buildYearlyAmortization(schedule);
renderChart(yearly);
renderTable(yearly, 'year');
// Tab switching
document.getElementById('yearTab').onclick = function() {
this.classList.add('active');
document.getElementById('monthTab').classList.remove('active');
renderTable(yearly, 'year');
};
document.getElementById('monthTab').onclick = function() {
this.classList.add('active');
document.getElementById('yearTab').classList.remove('active');
renderTable(schedule, 'month');
};
}
document.getElementById('loanForm').onsubmit = function(e) {
e.preventDefault();
calcAndRender();
};
// Set start date to today by default
window.onload = function() {
let today = new Date();
let yyyy = today.getFullYear();
let mm = String(today.getMonth() + 1).padStart(2, '0');
let dd = String(today.getDate()).padStart(2, '0');
document.getElementById('startDate').value = yyyy + '-' + mm + '-' + dd;
calcAndRender();
};