Intro – Build a Responsive Mortgage Calculator in React
Creating a Mortgage Calculator is a great project for those looking to combine financial logic with a user-friendly interface. This article will guide you through building a Mortgage Calculator using React, TypeScript, and Tailwind CSS for styling. We’ll also make our UI responsive and include a detailed amortization schedule.
Step 1: Project Setup
Create a new React project using Create React App with the TypeScript template. Install Tailwind CSS for styling.
npx create-react-app mortgage-calculator --template typescript
npx tailwindcss init -p
Step 2: Create Mortgage Calculator Component
Create a new file MortgageCalculator.tsx
. Define your state variables using the useState
hook to store the values of the home price, down payment, loan term, interest rate, and other costs.
// src/MortgageCalculator.tsx
import React, { useState } from 'react';
const MortgageCalculator: React.FC = () => {
const [homePrice, setHomePrice] = useState<number>(400000);
// ... other state variables ...
return (
// ... JSX ...
);
}
export default MortgageCalculator;
Step 3: Build the Form UI
In the MortgageCalculator
component, create input fields for each state variable and a button to trigger the calculation. Utilize Tailwind CSS classes for styling.
// ... inside MortgageCalculator component ...
return (
<div className="flex flex-col p-4 m-4 bg-white rounded shadow-lg max-w-md mx-auto">
<label htmlFor="homePrice">Home Price:</label>
<input
type="number"
id="homePrice"
value={homePrice}
onChange={e => setHomePrice(+e.target.value)}
/>
{/* ... other input fields and labels ... */}
<button className="p-2 bg-blue-500 text-white rounded mb-4">
Calculate
</button>
</div>
);
Step 4: Implement Calculation Logic Define a function calculatePayment
to compute the monthly mortgage payment using the formula:
M=P[r(1+r)n]/[(1+r)n−1]
Where:
- M is your monthly payment.
- P is the principal loan amount.
- r is your monthly interest rate.
- n is your number of months.
const calculatePayment = () => {
const downPayment = (downPaymentPercentage / 100) * homePrice;
const principal = homePrice - downPayment;
setPrincipal(principal);
const monthlyInterestRate = interestRate / 12 / 100;
const n = loanTerm * 12;
const monthlyLoanPayment =
(principal *
monthlyInterestRate *
Math.pow(1 + monthlyInterestRate, n)) /
(Math.pow(1 + monthlyInterestRate, n) - 1);
const monthlyPropertyTax = ((propertyTaxRate / 100) * homePrice) / 12;
const monthlyHomeInsurance = homeInsurance / 12;
const monthlyPmiInsurance = pmiInsurance / 12;
const monthlyHoaFee = hoaFee / 12;
const monthlyOtherCosts = otherCosts / 12;
const totalMonthlyPayment =
monthlyLoanPayment +
monthlyPropertyTax +
monthlyHomeInsurance +
monthlyPmiInsurance +
monthlyHoaFee +
monthlyOtherCosts;
setMonthlyPayment(totalMonthlyPayment);
};
Step 5: Create Amortization Schedule Component
Create a new component AmortizationSchedule.tsx
to display the amortization schedule. Pass the necessary props from the MortgageCalculator
component.
// AmortizationSchedule.tsx
import React from "react";
interface AmortizationScheduleProps {
principal: number;
monthlyInterestRate: number;
monthlyPayment: number;
loanTermMonths: number;
}
const AmortizationSchedule: React.FC<AmortizationScheduleProps> = ({
principal,
monthlyInterestRate,
monthlyPayment,
loanTermMonths,
}) => {
const calculateSchedule = () => {
let remainingBalance = principal;
const schedule = [];
for (let month = 1; month <= loanTermMonths; month++) {
const interestForMonth = remainingBalance * monthlyInterestRate;
const principalForMonth = monthlyPayment - interestForMonth;
remainingBalance -= principalForMonth;
schedule.push({
month,
monthlyPayment,
principalForMonth,
interestForMonth,
remainingBalance: remainingBalance < 0 ? 0 : remainingBalance,
});
}
return schedule;
};
const schedule = calculateSchedule();
return (
<div className="mt-4 overflow-x-auto">
<table className="min-w-full text-sm bg-white shadow-md rounded-lg">
<thead>
<tr className="text-gray-700 border-b">
<th className="px-4 py-2">Month</th>
<th className="px-4 py-2">Monthly Payment</th>
<th className="px-4 py-2">Principal</th>
<th className="px-4 py-2">Interest</th>
<th className="px-4 py-2">Remaining Balance</th>
</tr>
</thead>
<tbody>
{schedule.map((entry, index) => (
<tr
key={index}
className={index % 2 === 0 ? "bg-gray-100" : ""}
>
<td className="px-4 py-2">{entry.month}</td>
<td className="px-4 py-2">
${entry.monthlyPayment.toFixed(2)}
</td>
<td className="px-4 py-2">
${entry.principalForMonth.toFixed(2)}
</td>
<td className="px-4 py-2">
${entry.interestForMonth.toFixed(2)}
</td>
<td className="px-4 py-2">
${entry.remainingBalance.toFixed(2)}
</td>
</tr>
))}
</tbody>
</table>
</div>
);
};
export default AmortizationSchedule;
Complete Code
// MortgageCalculator.tsx
import React, { useState } from "react";
import AmortizationSchedule from "./AmortizationSchedule";
const MortgageCalculator: React.FC = () => {
const [homePrice, setHomePrice] = useState<number>(400000);
const [downPaymentPercentage, setDownPaymentPercentage] =
useState<number>(20);
const [loanTerm, setLoanTerm] = useState<number>(30);
const [interestRate, setInterestRate] = useState<number>(7.03);
const [propertyTaxRate, setPropertyTaxRate] = useState<number>(1.2);
const [homeInsurance, setHomeInsurance] = useState<number>(1500);
const [pmiInsurance, setPmiInsurance] = useState<number>(0);
const [hoaFee, setHoaFee] = useState<number>(0);
const [otherCosts, setOtherCosts] = useState<number>(4000);
const [monthlyPayment, setMonthlyPayment] = useState<number | null>(null);
const [principal, setPrincipal] = useState<number | null>(null);
const calculatePayment = () => {
const downPayment = (downPaymentPercentage / 100) * homePrice;
const principal = homePrice - downPayment;
setPrincipal(principal);
const monthlyInterestRate = interestRate / 12 / 100;
const n = loanTerm * 12;
const monthlyLoanPayment =
(principal *
monthlyInterestRate *
Math.pow(1 + monthlyInterestRate, n)) /
(Math.pow(1 + monthlyInterestRate, n) - 1);
const monthlyPropertyTax = ((propertyTaxRate / 100) * homePrice) / 12;
const monthlyHomeInsurance = homeInsurance / 12;
const monthlyPmiInsurance = pmiInsurance / 12;
const monthlyHoaFee = hoaFee / 12;
const monthlyOtherCosts = otherCosts / 12;
const totalMonthlyPayment =
monthlyLoanPayment +
monthlyPropertyTax +
monthlyHomeInsurance +
monthlyPmiInsurance +
monthlyHoaFee +
monthlyOtherCosts;
setMonthlyPayment(totalMonthlyPayment);
};
return (
<div className="container mx-auto p-4">
<header className="mb-4">
<h1 className="text-2xl font-bold text-center">
Mortgage Calculator
</h1>
</header>
<div className="flex flex-col md:flex-row p-4 m-4 bg-white rounded shadow-lg max-w-5xl mx-auto">
<div className="flex-1 p-4">
<div className="flex flex-col">
<label
className="mb-1 text-gray-700"
htmlFor="homePrice"
>
Home Price:
</label>
<input
type="number"
id="homePrice"
value={homePrice}
onChange={(e) => setHomePrice(+e.target.value)}
placeholder="Home Price"
className="p-2 border rounded mb-4"
/>
</div>
<div className="flex flex-col">
<label
className="mb-1 text-gray-700"
htmlFor="downPaymentPercentage"
>
Down Payment (%):
</label>
<input
type="number"
id="downPaymentPercentage"
value={downPaymentPercentage}
onChange={(e) =>
setDownPaymentPercentage(+e.target.value)
}
placeholder="Down Payment"
className="p-2 border rounded mb-4"
/>
</div>
<div className="flex flex-col">
<label
className="mb-1 text-gray-700"
htmlFor="loanTerm"
>
Loan Term (years):
</label>
<input
type="number"
id="loanTerm"
value={loanTerm}
onChange={(e) => setLoanTerm(+e.target.value)}
placeholder="Loan Term"
className="p-2 border rounded mb-4"
/>
</div>
<div className="flex flex-col">
<label
className="mb-1 text-gray-700"
htmlFor="interestRate"
>
Interest Rate (%):
</label>
<input
type="number"
id="interestRate"
value={interestRate}
onChange={(e) => setInterestRate(+e.target.value)}
placeholder="Interest Rate"
className="p-2 border rounded mb-4"
/>
</div>
<div className="flex flex-col">
<label
className="mb-1 text-gray-700"
htmlFor="propertyTaxRate"
>
Property Tax Rate (%):
</label>
<input
type="number"
id="propertyTaxRate"
value={propertyTaxRate}
onChange={(e) =>
setPropertyTaxRate(+e.target.value)
}
placeholder="Property Tax Rate"
className="p-2 border rounded mb-4"
/>
</div>
<div className="flex flex-col">
<label
className="mb-1 text-gray-700"
htmlFor="homeInsurance"
>
Home Insurance ($):
</label>
<input
type="number"
id="homeInsurance"
value={homeInsurance}
onChange={(e) => setHomeInsurance(+e.target.value)}
placeholder="Home Insurance"
className="p-2 border rounded mb-4"
/>
</div>
<div className="flex flex-col">
<label
className="mb-1 text-gray-700"
htmlFor="pmiInsurance"
>
PMI Insurance ($):
</label>
<input
type="number"
id="pmiInsurance"
value={pmiInsurance}
onChange={(e) => setPmiInsurance(+e.target.value)}
placeholder="PMI Insurance"
className="p-2 border rounded mb-4"
/>
</div>
<div className="flex flex-col">
<label className="mb-1 text-gray-700" htmlFor="hoaFee">
HOA Fee ($):
</label>
<input
type="number"
id="hoaFee"
value={hoaFee}
onChange={(e) => setHoaFee(+e.target.value)}
placeholder="HOA Fee"
className="p-2 border rounded mb-4"
/>
</div>
<div className="flex flex-col">
<label
className="mb-1 text-gray-700"
htmlFor="otherCosts"
>
Other Costs ($):
</label>
<input
type="number"
id="otherCosts"
value={otherCosts}
onChange={(e) => setOtherCosts(+e.target.value)}
placeholder="Other Costs"
className="p-2 border rounded mb-4"
/>
</div>
{/* ... similarly add input fields for homeInsurance, pmiInsurance, hoaFee, and otherCosts ... */}
<button
onClick={calculatePayment}
className="p-2 bg-blue-500 hover:bg-blue-700 text-white rounded mb-4 w-full transition duration-300 ease-in-out"
>
Calculate
</button>
</div>
{monthlyPayment !== null && (
<div>
<div className="text-lg font-bold mb-4">
Monthly Payment: ${monthlyPayment.toFixed(2)}
</div>
{principal && (
<AmortizationSchedule
principal={principal}
monthlyInterestRate={interestRate / 12 / 100}
monthlyPayment={monthlyPayment}
loanTermMonths={loanTerm * 12}
/>
)}
</div>
)}
</div>
</div>
);
};
export default MortgageCalculator;
💁 Check out our other articles😃
👉 Generate a free Developer Portfolio website with AI prompts
👉 Build a Simple Calculator App with React, Tailwind CSS. Displays History
Conclusion
With these steps, you have built a functional, responsive Mortgage Calculator in React. This project showcases how you can combine financial logic, React components, and Tailwind CSS to create a useful, user-friendly application.