Enter Your Tax Information (2025 Tax Year)
Your total income before deductions.
Gains from assets held over 1 year.
Eligible dividends taxed at capital gains rates.
Adjustments to income (above-the-line).
Your Tax Analysis (2025 Tax Year)
Income Breakdown by Tax Bracket
2025 Federal Income Tax Brackets (Estimated)
These are estimated tax brackets for the 2025 tax year, for illustrative purposes. Always consult official IRS resources or a tax professional for accurate tax planning.
Single Filers
| Tax Rate | Taxable Income |
|---|
Married Filing Jointly
| Tax Rate | Taxable Income |
|---|
Head of Household
| Tax Rate | Taxable Income |
|---|
Please enter valid non-negative numeric values for all fields.
"; showTab('results'); return; } // Calculate total deductions (Standard Deduction + Other Deductions) let totalDeductions = standardDeductions[filingStatus] + otherDeductions; // Ensure deductions don't exceed gross income totalDeductions = Math.min(totalDeductions, grossIncome); // Calculate Adjusted Gross Income (AGI) - simplified for this tool let AGI = grossIncome - otherDeductions; AGI = Math.max(0, AGI); // AGI cannot be negative // Calculate ordinary taxable income before capital gains/qualified dividends let ordinaryTaxableIncome = AGI - standardDeductions[filingStatus]; ordinaryTaxableIncome = Math.max(0, ordinaryTaxableIncome); // Taxable income cannot be negative // Separate ordinary income and capital gains/qualified dividends // For simplicity, assume all qualified dividends are treated as long-term capital gains for tax rate purposes let combinedCapitalGainsIncome = longTermCapitalGains + qualifiedDividends; let totalTaxableIncome = ordinaryTaxableIncome + combinedCapitalGainsIncome; // --- Calculate Tax Liability --- let totalTaxLiability = 0; let marginalRate = 0; let effectiveRate = 0; let bracketBreakdownHtml = ''; // First, calculate tax on ordinary income using progressive brackets let remainingOrdinaryIncome = ordinaryTaxableIncome; let ordinaryTaxDetails = []; for (const bracket of taxBrackets[filingStatus]) { if (remainingOrdinaryIncome <= 0) break; const bracketMin = bracket.min; const bracketMax = bracket.max; const bracketRate = bracket.rate; let taxedInBracket = 0; if (remainingOrdinaryIncome > bracketMax && bracketMax !== Infinity) { taxedInBracket = (bracketMax - Math.max(bracketMin, 0)) + 1; // Amount within the bracket range } else { taxedInBracket = remainingOrdinaryIncome - Math.max(bracketMin, 0); } taxedInBracket = Math.max(0, taxedInBracket); // Ensure not negative const taxInThisBracket = taxedInBracket * bracketRate; totalTaxLiability += taxInThisBracket; remainingOrdinaryIncome -= taxedInBracket; if (taxedInBracket > 0) { ordinaryTaxDetails.push({ type: 'Ordinary Income', amount: taxedInBracket, rate: bracketRate, tax: taxInThisBracket, bracketRange: `\$${bracket.min.toLocaleString()} - \$${bracket.max === Infinity ? 'and up' : bracket.max.toLocaleString()}` }); } // The marginal rate is the rate of the highest bracket income falls into if (ordinaryTaxableIncome > bracketMin) { marginalRate = bracketRate; } } // Now, calculate tax on Long-Term Capital Gains / Qualified Dividends let remainingCapitalGains = combinedCapitalGainsIncome; let capitalGainsTaxDetails = []; // The income for capital gains rates is *total* taxable income, including ordinary income. // The 0%, 15%, 20% thresholds are based on your overall taxable income. // Find the capital gains brackets relevant to the filing status const currentCapitalGainsBrackets = capitalGainsBrackets[filingStatus]; for (const cgBracket of currentCapitalGainsBrackets) { if (remainingCapitalGains <= 0) break; const cgRate = cgBracket.rate; const cgMaxThreshold = cgBracket.max; // This is the total income threshold for this CG rate // Determine how much of the combined capital gains income falls into this CG bracket // This logic is simplified; a true calculation requires more complex integration with ordinary income. // For this tool, we will assume capital gains are taxed *on top* of ordinary income. // This means we need to find which CG bracket the *total* taxable income (ordinary + CG) falls into. let effectiveIncomeForCgBracket = totalTaxableIncome; if (cgMaxThreshold !== Infinity && effectiveIncomeForCgBracket > cgMaxThreshold) { // The amount of capital gains taxed at this rate is limited by the threshold const amountAtThisRate = Math.min(remainingCapitalGains, cgMaxThreshold - (totalTaxableIncome - remainingCapitalGains)); if (amountAtThisRate > 0) { const tax = amountAtThisRate * cgRate; totalTaxLiability += tax; remainingCapitalGains -= amountAtThisRate; capitalGainsTaxDetails.push({ type: 'Long-Term Capital Gains/Qualified Dividends', amount: amountAtThisRate, rate: cgRate, tax: tax, bracketRange: `Total Income up to \$${cgMaxThreshold.toLocaleString()}` }); marginalRate = Math.max(marginalRate, cgRate); // Update marginal rate if higher } } else if (remainingCapitalGains > 0) { // All remaining capital gains fall into this bracket or higher const tax = remainingCapitalGains * cgRate; totalTaxLiability += tax; capitalGainsTaxDetails.push({ type: 'Long-Term Capital Gains/Qualified Dividends', amount: remainingCapitalGains, rate: cgRate, tax: tax, bracketRange: `Total Income \$${(cgBracket.max === Infinity ? 'and up' : (cgBracket.max + 1).toLocaleString())}` }); marginalRate = Math.max(marginalRate, cgRate); // Update marginal rate if higher remainingCapitalGains = 0; // All accounted for } } // Calculate Effective Tax Rate if (totalTaxableIncome > 0) { effectiveRate = (totalTaxLiability / totalTaxableIncome) * 100; } else { effectiveRate = 0; } // --- Display Results --- displayElements.displayGrossIncome.textContent = `$${grossIncome.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`; displayElements.displayTotalDeductions.textContent = `$${totalDeductions.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`; displayElements.displayTaxableIncome.textContent = `$${totalTaxableIncome.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`; displayElements.displayTaxLiability.textContent = `$${totalTaxLiability.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`; displayElements.displayMarginalRate.textContent = `${(marginalRate * 100).toFixed(0)}%`; displayElements.displayEffectiveRate.textContent = `${effectiveRate.toFixed(2)}%`; // Build Bracket Breakdown HTML bracketBreakdownHtml += `Ordinary Income Breakdown:
`; if (ordinaryTaxDetails.length === 0 && ordinaryTaxableIncome === 0) { bracketBreakdownHtml += `No ordinary taxable income.
`; } else { ordinaryTaxDetails.forEach(detail => { bracketBreakdownHtml += `Taxed \$${detail.amount.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })} at ${(detail.rate * 100).toFixed(0)}% (${detail.bracketRange}) = \$${detail.tax.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}
`; }); } if (combinedCapitalGainsIncome > 0) { bracketBreakdownHtml += `Long-Term Capital Gains / Qualified Dividends Breakdown:
`; if (capitalGainsTaxDetails.length > 0) { capitalGainsTaxDetails.forEach(detail => { bracketBreakdownHtml += `Taxed \$${detail.amount.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })} at ${(detail.rate * 100).toFixed(0)}% (${detail.bracketRange}) = \$${detail.tax.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}
`; }); } else { bracketBreakdownHtml += `No long-term capital gains/qualified dividends taxed or all fell into 0% bracket.
`; } } displayElements.bracketBreakdown.innerHTML = bracketBreakdownHtml; showTab('results'); // Switch to results tab after calculation } // --- PDF Download Functionality --- controlButtons.downloadPdf.addEventListener('click', function() { try { const { jsPDF } = window.jspdf; const doc = new jsPDF('p', 'mm', 'a4'); const margin = 20; let yPos = margin; // Title doc.setFont("helvetica", "bold"); doc.setFontSize(20); doc.setTextColor(37, 99, 235); /* Blue */ doc.text('Tax Bracket Analysis Report for Investors', doc.internal.pageSize.width / 2, yPos, { align: 'center' }); yPos += 15; // Tax Year and Disclaimer doc.setFont("helvetica", "normal"); doc.setFontSize(10); doc.setTextColor(107, 114, 128); /* Gray */ doc.text('Analysis for 2025 Tax Year (Estimated Brackets)', doc.internal.pageSize.width / 2, yPos, { align: 'center' }); yPos += 7; doc.text('Disclaimer: This report is an estimation for illustrative purposes only and should not be considered tax advice.', doc.internal.pageSize.width / 2, yPos, { align: 'center' }); yPos += 15; // Input Parameters doc.setFont("helvetica", "bold"); doc.setFontSize(14); doc.setTextColor(75, 85, 99); /* Dark Gray */ doc.text('Input Parameters', margin, yPos); yPos += 8; const inputData = [ ["Gross Income", `$${parseFloat(inputElements.grossIncome.value).toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`], ["Filing Status", inputElements.filingStatus.options[inputElements.filingStatus.selectedIndex].text], ["Long-Term Capital Gains", `$${parseFloat(inputElements.longTermCapitalGains.value).toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`], ["Qualified Dividends", `$${parseFloat(inputElements.qualifiedDividends.value).toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`], ["Other Deductions", `$${parseFloat(inputElements.otherDeductions.value).toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`] ]; doc.autoTable({ startY: yPos, head: [['Parameter', 'Value']], body: inputData, theme: 'grid', styles: { fontSize: 10, cellPadding: 3, textColor: '#333', lineColor: '#eee', lineWidth: 0.1 }, headStyles: { fillColor: '#eef2ff', textColor: '#374151', fontStyle: 'bold' }, margin: { left: margin, right: margin } }); yPos = doc.autoTable.previous.finalY + 15; // Calculation Results doc.setFont("helvetica", "bold"); doc.setFontSize(14); doc.setTextColor(75, 85, 99); doc.text('Calculation Results', margin, yPos); yPos += 8; const resultsData = [ ["Gross Income", displayElements.displayGrossIncome.textContent], ["Total Deductions", displayElements.displayTotalDeductions.textContent], ["Taxable Income", displayElements.displayTaxableIncome.textContent], ["Total Tax Liability", displayElements.displayTaxLiability.textContent], ["Marginal Tax Rate", displayElements.displayMarginalRate.textContent], ["Effective Tax Rate", displayElements.displayEffectiveRate.textContent] ]; doc.autoTable({ startY: yPos, head: [['Metric', 'Value']], body: resultsData, theme: 'grid', styles: { fontSize: 10, cellPadding: 3, textColor: '#333', lineColor: '#eee', lineWidth: 0.1 }, headStyles: { fillColor: '#eef2ff', textColor: '#374151', fontStyle: 'bold' }, margin: { left: margin, right: margin } }); yPos = doc.autoTable.previous.finalY + 15; // Income Breakdown by Tax Bracket doc.setFont("helvetica", "bold"); doc.setFontSize(14); doc.setTextColor(75, 85, 99); doc.text('Income Breakdown by Tax Bracket', margin, yPos); yPos += 8; // Capture the bracket breakdown HTML content const bracketBreakdownHtml = displayElements.bracketBreakdown.innerHTML; // For autoTable, we need structured data, so parse the breakdown. // This is a simplified parsing. For complex dynamic content, consider html2canvas or more robust PDF generation. const breakdownLines = bracketBreakdownHtml.split('').filter(line => line.trim() !== '').map(line => { const text = line.replace(/<[^>]*>/g, '').trim(); // Remove HTML tags return [text]; }); doc.autoTable({ startY: yPos, body: breakdownLines, theme: 'plain', // Use plain theme for breakdown text styles: { fontSize: 9, cellPadding: 2, textColor: '#333' }, columnStyles: { 0: { cellWidth: 'wrap' } }, margin: { left: margin, right: margin } }); yPos = doc.autoTable.previous.finalY + 15; // Add Tax Brackets Table doc.addPage(); // Start new page for brackets if content is long yPos = margin; // Reset Y position for new page doc.setFont("helvetica", "bold"); doc.setFontSize(16); doc.setTextColor(37, 99, 235); doc.text('2025 Federal Income Tax Brackets (Estimated)', doc.internal.pageSize.width / 2, yPos, { align: 'center' }); yPos += 15; // Single Filers Table doc.setFont("helvetica", "bold"); doc.setFontSize(12); doc.setTextColor(75, 85, 99); doc.text('Single Filers', margin, yPos); yPos += 8; const singleBracketData = taxBrackets["single"].map(b => [ `${(b.rate * 100).toFixed(0)}%`, b.max === Infinity ? `\$${b.min.toLocaleString()} or more` : `\$${b.min.toLocaleString()} to \$${b.max.toLocaleString()}` ]); doc.autoTable({ startY: yPos, head: [['Tax Rate', 'Taxable Income']], body: singleBracketData, theme: 'grid', styles: { fontSize: 9, cellPadding: 2, textColor: '#333', lineColor: '#eee', lineWidth: 0.1 }, headStyles: { fillColor: '#eef2ff', textColor: '#374151', fontStyle: 'bold' }, margin: { left: margin, right: margin } }); yPos = doc.autoTable.previous.finalY + 10; // Married Filing Jointly Table doc.setFont("helvetica", "bold"); doc.setFontSize(12); doc.setTextColor(75, 85, 99); doc.text('Married Filing Jointly', margin, yPos); yPos += 8; const marriedJointlyBracketData = taxBrackets["marriedJointly"].map(b => [ `${(b.rate * 100).toFixed(0)}%`, b.max === Infinity ? `\$${b.min.toLocaleString()} or more` : `\$${b.min.toLocaleString()} to \$${b.max.toLocaleString()}` ]); doc.autoTable({ startY: yPos, head: [['Tax Rate', 'Taxable Income']], body: marriedJointlyBracketData, theme: 'grid', styles: { fontSize: 9, cellPadding: 2, textColor: '#333', lineColor: '#eee', lineWidth: 0.1 }, headStyles: { fillColor: '#eef2ff', textColor: '#374151', fontStyle: 'bold' }, margin: { left: margin, right: margin } }); yPos = doc.autoTable.previous.finalY + 10; // Head of Household Table doc.setFont("helvetica", "bold"); doc.setFontSize(12); doc.setTextColor(75, 85, 99); doc.text('Head of Household', margin, yPos); yPos += 8; const headOfHouseholdBracketData = taxBrackets["headOfHousehold"].map(b => [ `${(b.rate * 100).toFixed(0)}%`, b.max === Infinity ? `\$${b.min.toLocaleString()} or more` : `\$${b.min.toLocaleString()} to \$${b.max.toLocaleString()}` ]); doc.autoTable({ startY: yPos, head: [['Tax Rate', 'Taxable Income']], body: headOfHouseholdBracketData, theme: 'grid', styles: { fontSize: 9, cellPadding: 2, textColor: '#333', lineColor: '#eee', lineWidth: 0.1 }, headStyles: { fillColor: '#eef2ff', textColor: '#374151', fontStyle: 'bold' }, margin: { left: margin, right: margin } }); yPos = doc.autoTable.previous.finalY + 10; doc.save('Tax_Bracket_Analysis_Report.pdf'); } catch (error) { console.error("Error generating PDF:", error); // In a real application, you'd show a user-friendly modal here instead of just logging. // For example: // const errorModal = document.createElement('div'); // errorModal.textContent = "Failed to generate PDF. Please try again or check console for details."; // errorModal.style.cssText = "position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);background:red;color:white;padding:15px;border-radius:8px;z-index:9999;"; // document.body.appendChild(errorModal); // setTimeout(() => document.body.removeChild(errorModal), 5000); } }); // Initial population of tax bracket tables populateTaxBracketTables(); // Initial tab display showTab('inputs'); });