Mortgage Calculator

Free Monthly Home Loan Calculator.

Mortgage Loan Details

$
$
%
%
$
$
$
$

Monthly Payment Breakdown

Based on your inputted interest rate of 6.700%

$3,121/mo
Principal & Interest $2,774.70
Property Tax $280.00
Homeowners Insurance $66.00
PMI $0.00
HOA Fees $0.00
Total Monthly Payment $3,120.70

Amortization for Mortgage Loan

Amortization is paying off debt over time in equal installments. A larger share of your payment goes toward principal as the loan progresses.

Based on your inputted interest rate of 6.700%

Loan Amount
$430,000
Total Interest Paid
$568,891
Total Cost of Loan
$998,891
Payoff Date
May 2055

Loan Balance Over Time

Loan Balance
Principal Paid
Interest Paid

Extra Payments?

$
$
$

Amortization Schedule Breakdown

This table shows principal and interest for each payment.

First payment: | Last payment:
| |
`); printWindow.document.close(); printWindow.print(); });exportCsvBtn.addEventListener('click', () => { const rows = [["Year", "Month", "Principal", "Interest", "Remaining Balance"]]; amortizationTableBody.querySelectorAll('details').forEach(detail => { const year = detail.querySelector('summary .summary-year').textContent; detail.querySelectorAll('.monthly-table tbody tr').forEach(row => { const cells = Array.from(row.querySelectorAll('td')).map(td => { const text = td.textContent.replace(/[^0-9A-Za-z\s.]/g, ''); return `"${text.replace(/"/g, '""')}"`; }); rows.push([year, ...cells]); }); }); const csvContent = "data:text/csv;charset=utf-8," + rows.map(e => e.join(",")).join("\n"); const link = document.createElement("a"); link.setAttribute("href", encodeURI(csvContent)); link.setAttribute("download", "amortization_schedule.csv"); document.body.appendChild(link); link.click(); document.body.removeChild(link); });// --- CORE LOGIC --- function updateMonthlyInputs() { taxMonthlyInput.value = formatInput(parseCurrency(propertyTaxInput.value)); insMonthlyInput.value = formatInput(parseCurrency(homeInsuranceInput.value)); pmiMonthlyInput.value = formatInput(parseCurrency(pmiInput.value)); hoaMonthlyInput.value = formatInput(parseCurrency(hoaInput.value)); taxMonthlyDisplay.textContent = formatCurrency(parseCurrency(taxMonthlyInput.value)); insMonthlyDisplay.textContent = formatCurrency(parseCurrency(insMonthlyInput.value)); pmiMonthlyDisplay.textContent = formatCurrency(parseCurrency(pmiMonthlyInput.value)); hoaMonthlyDisplay.textContent = formatCurrency(parseCurrency(hoaMonthlyInput.value)); }function getFormValues() { const homePrice = parseCurrency(homePriceInput.value); const dpAmount = parseCurrency(dpAmountInput.value); const loanAmount = Math.max(0, homePrice - dpAmount); const startDate = startDateInput.value ? new Date(startDateInput.value) : new Date(); const oneTimeDate = oneTimeDateInput.value ? new Date(oneTimeDateInput.value) : new Date(); return { homePrice, dpAmount, dpPercent: parseFloat(dpPercentInput.value) || 0, loanTerm: parseInt(loanTermSelect.value, 10), annualRate: parseFloat(interestRateInput.value) || 0, loanAmount, taxMonthly: parseCurrency(propertyTaxInput.value), insMonthly: parseCurrency(homeInsuranceInput.value), pmiMonthly: parseCurrency(pmiInput.value), hoaMonthly: parseCurrency(hoaInput.value), extraMonthly: parseCurrency(extraMonthlyInput.value), extraYearly: parseCurrency(extraYearlyInput.value), oneTimeAmount: parseCurrency(oneTimeAmountInput.value), oneTimeDate, startDate }; }function calculateAndDisplay() { loadingSpinner.classList.add('active'); setTimeout(() => { const form = getFormValues(); const monthlyRate = form.annualRate / 1200; const numPayments = form.loanTerm * 12;let pni = 0; if (form.loanAmount > 0 && numPayments > 0) { if (monthlyRate > 0) { pni = form.loanAmount * (monthlyRate * Math.pow(1 + monthlyRate, numPayments)) / (Math.pow(1 + monthlyRate, numPayments) - 1); } else { pni = form.loanAmount / numPayments; } } const pniDisplay = Number(pni.toFixed(2)); pniDisplayEl.textContent = formatCurrency(pniDisplay); document.getElementById('pni-monthly').value = formatInput(pniDisplay); updateMonthlyInputs();const payments = { pni: pniDisplay, taxMonthly: form.taxMonthly, insMonthly: form.insMonthly, pmiMonthly: form.pmiMonthly, hoaMonthly: form.hoaMonthly };const amortizationData = generateAmortization( form.loanAmount, monthlyRate, pni, numPayments, form.extraMonthly, form.extraYearly, form.oneTimeAmount, form.oneTimeDate, form.startDate ); updateUI(payments, form, amortizationData); loadingSpinner.classList.remove('active'); doughnutChartEl.classList.add('updated'); setTimeout(() => doughnutChartEl.classList.remove('updated'), 300); }, 100); }function generateAmortization(principal, monthlyRate, pni, totalPayments, extraMonthly, extraYearly, oneTimeAmount, oneTimeDate, startDate) { if (principal <= 0 || totalPayments <= 0) { return { yearlyData: {}, monthlyData: [], totalInterest: 0, firstPaymentDate: new Date(), lastPaymentDate: new Date() }; }let balance = principal; let totalInterest = 0; const firstPaymentDate = new Date(startDate.getFullYear(), startDate.getMonth() + 1, 1); let currentDate = new Date(firstPaymentDate); let lastPaymentDate = currentDate; const monthlyData = []; const yearlyData = {}; let oneTimeApplied = false;for (let i = 0; i < totalPayments && balance > 0.01; i++) { const year = currentDate.getFullYear(); const isYearStart = currentDate.getMonth() === 0;const interestPayment = balance * monthlyRate; let principalPayment = pni - interestPayment + extraMonthly;if (isYearStart && extraYearly > 0 && currentDate > firstPaymentDate) { principalPayment += extraYearly; }if (!oneTimeApplied && oneTimeAmount > 0 && currentDate >= oneTimeDate) { principalPayment += oneTimeAmount; oneTimeApplied = true; }if (principalPayment > balance) { principalPayment = balance; }balance -= principalPayment; totalInterest += interestPayment; lastPaymentDate = new Date(currentDate);monthlyData.push({ date: new Date(currentDate), interest: Number(interestPayment.toFixed(2)), principal: Number(principalPayment.toFixed(2)), balance: Number(Math.max(balance, 0).toFixed(2)) });if (!yearlyData[year]) { yearlyData[year] = { months: [], totalPrincipal: 0, totalInterest: 0, endBalance: 0 }; } yearlyData[year].months.push(monthlyData[monthlyData.length - 1]); yearlyData[year].totalPrincipal += principalPayment; yearlyData[year].totalInterest += interestPayment; yearlyData[year].endBalance = Math.max(balance, 0);currentDate.setMonth(currentDate.getMonth() + 1); }Object.keys(yearlyData).forEach(year => { yearlyData[year].totalPrincipal = Number(yearlyData[year].totalPrincipal.toFixed(2)); yearlyData[year].totalInterest = Number(yearlyData[year].totalInterest.toFixed(2)); yearlyData[year].endBalance = Number(yearlyData[year].endBalance.toFixed(2)); });return { yearlyData, monthlyData, totalInterest: Number(totalInterest.toFixed(2)), firstPaymentDate, lastPaymentDate }; }function updateUI(payments, form, amortizationData) { const { pni, taxMonthly, insMonthly, pmiMonthly, hoaMonthly } = payments; const { yearlyData, monthlyData, totalInterest, firstPaymentDate, lastPaymentDate } = amortizationData;dynamicRateEl.textContent = dynamicRateAmortEl.textContent = form.annualRate.toFixed(3); const totalMonthly = Number((pni + taxMonthly + insMonthly + pmiMonthly + hoaMonthly).toFixed(2)); totalMonthlyPaymentEl.textContent = formatCurrency(totalMonthly);doughnutChartEl.innerHTML = `${formatCurrency(totalMonthly).replace('.00', '')}/mo`; if (totalMonthly > 0) { const pniP = (pni / totalMonthly) * 100; const taxP = (taxMonthly / totalMonthly) * 100; const insP = (insMonthly / totalMonthly) * 100; const pmiP = (pmiMonthly / totalMonthly) * 100; doughnutChartEl.style.backgroundImage = `conic-gradient( var(--br-chart-pni) 0% ${pniP}%, var(--br-chart-tax) ${pniP}% ${pniP + taxP}%, var(--br-chart-ins) ${pniP + taxP}% ${pniP + taxP + insP}%, var(--br-chart-pmi) ${pniP + taxP + insP}% ${pniP + taxP + insP + pmiP}%, var(--br-chart-hoa) ${pniP + taxP + insP + pmiP}% 100% )`; } else { doughnutChartEl.style.backgroundImage = 'conic-gradient(#eee 0% 100%)'; }const payoffDateStr = lastPaymentDate.toLocaleString('default', { month: 'long', year: 'numeric' }); summaryLoanAmountEl.textContent = formatCurrency(form.loanAmount); summaryTotalInterestEl.textContent = formatCurrency(totalInterest); summaryTotalCostEl.textContent = formatCurrency(Number((form.loanAmount + totalInterest).toFixed(2))); summaryPayoffDateEl.textContent = payoffDateStr; firstPaymentDateEl.textContent = firstPaymentDate.toLocaleString('default', { month: 'long', year: 'numeric' }); lastPaymentDateEl.textContent = payoffDateStr;updateAmortizationGraph(yearlyData, form.loanAmount, totalInterest); updateAmortizationTable(yearlyData); }function updateAmortizationGraph(yearlyData, loanAmount, totalInterest) { const svg = document.getElementById('amortization-chart-svg'); svg.innerHTML = ''; if (Object.keys(yearlyData).length === 0 || loanAmount <= 0) { svg.innerHTML = 'No data to display'; return; }const allMonths = Object.values(yearlyData).flatMap(y => y.months); if (allMonths.length === 0) return;const width = 400, height = 220, m = { top: 20, right: 20, bottom: 35, left: 50 }; const w = width - m.left - m.right, h = height - m.top - m.bottom; const maxY = Math.max(loanAmount, totalInterest, 1);const g = document.createElementNS("http://www.w3.org/2000/svg", "g"); g.setAttribute("transform", `translate(${m.left},${m.top})`); svg.appendChild(g);const xScale = i => (i / (allMonths.length - 1)) * w; const yScale = v => h - (v / maxY) * h;const createPath = (data, color) => { const path = document.createElementNS("http://www.w3.org/2000/svg", "path"); path.setAttribute('d', `M0,${yScale(data[0])} ` + data.slice(1).map((d, i) => `L${xScale(i + 1)},${yScale(d)}`).join(' ')); path.setAttribute('class', 'line'); path.style.stroke = color; path.style.strokeWidth = '2.5'; path.style.opacity = '0.9'; return path; };let cumulativePrincipal = 0, cumulativeInterest = 0; const balanceData = allMonths.map(d => d.balance < 0 ? 0 : d.balance); const principalData = allMonths.map(d => (cumulativePrincipal += d.principal, Math.min(cumulativePrincipal, maxY))); const interestData = allMonths.map(d => (cumulativeInterest += d.interest, Math.min(cumulativeInterest, maxY)));[createPath(balanceData, 'var(--br-chart-balance)'), createPath(principalData, 'var(--br-chart-principal)'), createPath(interestData, 'var(--br-chart-interest)')].forEach(path => g.appendChild(path));for (let i = 0; i <= 5; i++) { const y = h * (i / 5); const line = document.createElementNS("http://www.w3.org/2000/svg", "line"); line.setAttribute('x1', 0); line.setAttribute('x2', w); line.setAttribute('y1', y); line.setAttribute('y2', y); line.setAttribute('class', 'grid'); g.appendChild(line); const text = document.createElementNS("http://www.w3.org/2000/svg", "text"); text.setAttribute('x', -10); text.setAttribute('y', y + 4); text.setAttribute('class', 'axis-label'); text.setAttribute('text-anchor', 'end'); text.textContent = `$${(maxY * (1 - i / 5) / 1000).toFixed(0)}k`; g.appendChild(text); }const yearKeys = Object.keys(yearlyData).sort(); const step = Math.max(1, Math.ceil(yearKeys.length / 6)); for (let i = 0; i < yearKeys.length; i += step) { const year = yearKeys[i]; const monthIndex = allMonths.findIndex(d => d.date.getFullYear() == year); if (monthIndex < 0) continue; const x = xScale(monthIndex); const line = document.createElementNS("http://www.w3.org/2000/svg", "line"); line.setAttribute('x1', x); line.setAttribute('x2', x); line.setAttribute('y1', 0); line.setAttribute('y2', h); line.setAttribute('class', 'grid'); g.appendChild(line); const text = document.createElementNS("http://www.w3.org/2000/svg", "text"); text.setAttribute('x', x); text.setAttribute('y', h + 20); text.setAttribute('class', 'axis-label'); text.setAttribute('text-anchor', 'middle'); text.textContent = year; g.appendChild(text); } }function updateAmortizationTable(yearlyData) { amortizationTableBody.innerHTML = ''; Object.keys(yearlyData).sort().forEach(year => { const yearData = yearlyData[year]; const details = document.createElement('details'); details.innerHTML = ` ${year} ${formatCurrency(yearData.totalPrincipal)} ${formatCurrency(yearData.totalInterest)} ${formatCurrency(yearData.endBalance)}
${yearData.months.map(row => ` `).join('')}
MonthPrincipalInterestRemaining Balance
${row.date.toLocaleString('default', { month: 'long' })}${formatCurrency(row.principal)}${formatCurrency(row.interest)}${formatCurrency(row.balance)}
`; amortizationTableBody.appendChild(details); }); }calculateAndDisplay(); });

Why Choose Our Free PDF Merger?

Completely Free

Merge unlimited PDFs with no fees, no watermarks, and no hidden costs.

Lightning Fast

Combine files in seconds with our intuitive drag-and-drop interface.

Secure & Private

TLS encryption and auto-deletion keep your files safe.

Any Device

Merge PDFs on mobile, tablet, or desktop – no downloads needed.

Easy Organization

Preview, reorder, or delete pages before merging.

Cloud-Based

Save device resources with our efficient online processing.

Merge PDFs in 3 Simple Steps

  1. Upload PDFs: Click “Choose Files” or drag and drop your documents into the tool area above.
  2. Arrange Files: Drag and drop the file previews to set the perfect order for your new document.
  3. Merge & Save: Hit the “Merge PDF” button and download your combined file instantly.

Fast, Secure, and Free PDF Merging

Merge your PDF files quickly and easily into a single, professional document with AllWebToolkit. Our free online PDF merger is designed to be user-friendly, adding no watermarks and requiring no registration. Combine multiple PDFs in seconds and get a polished result every time.

Trusted by Thousands Worldwide

Join countless users who rely on our tool to combine PDFs seamlessly. Unlike other platforms like iLovePDF or Smallpdf, we offer unlimited merging without paywalls or restrictions, making us the go-to choice for students, professionals, and businesses.

More Free PDF Tools

Explore our suite of powerful, browser-based tools, all 100% free: