Description
- adding mortgage calculator
- view demo – password: abc
- buy me a coffee

#1. Install Code
This is just a calculator using a sample formula, but you can easily send it to AI (ChatGPT or Claude. I recommend this AI chat bot) to customize it to your specific needs – and, notably, it can sync with your Squarespace style. You can also use this free calculator tool to create a calculator.
#1.1. You can edit Page where you want to place Calculator > Add a Code Block

#1.2. Add this code into Code Block
<!-- 09.26c14v1(v2) Mortgage Caculator -->
<div class="tp-calc" data-tp-calc></div>
<script>
window.MortgageCalcConfig = {
text: {
title: "",
amountLabel: "Loan Amount",
amountHint: "Enter the total loan amount you want to borrow",
rateLabel: "Interest Rate",
rateUnit: "%",
rateHint: "",
periodLabel: "Loan Period",
periodUnit: "years",
periodHint: "",
paymentHeading: "Monthly Payment",
paymentHint: "This is an approximate monthly repayment amount for your mortgage based on the given inputs.",
interestLabel: "Total Interest Paid",
interestHint: "This is the total interest you would pay over the entire loan period.",
ctaHeading: "Ready to get started?",
ctaHint: "Get in touch with our mortgage advisors for personalized advice!",
ctaButton: "Book a Meeting",
ctaHref: "/contact-us"
},
tags: {
title: "h2",
amountLabel: "h3",
rateLabel: "h3",
periodLabel: "h3",
paymentHeading: "h3",
interestLabel: "h3",
ctaHeading: "h2"
},
colors: {
title: "",
label: "",
smallText: "",
cardBg: "#f0f6fd",
cardHeading: "",
cardValue: "",
cardMuted: "rgba(17,17,17,0.6)"
},
slider: {
trackFill: "#197bff",
trackEmpty: "rgba(17,17,17,0.05)",
thumbBg: "#ffffff",
thumbBorder: "rgba(17,17,17,0.1)",
trackHeight: "6px",
thumbSize: "24px"
},
layout: {
inputBorder: "1px solid rgba(17,17,17,0.2)"
},
button: {
text: "#ffffff",
bg: "#197bff",
border: "#197bff",
hoverText: "#ffffff",
hoverBg: "#1569e0",
hoverBorder: "#1569e0"
},
ranges: {
amount: { min: 100000, max: 5000000, step: 10000, value: 1000000 },
rate: { min: 1, max: 15, step: 0.1, value: 5 },
period: { min: 5, max: 40, step: 1, value: 30 }
},
formula: {
currencySymbol: "$",
moneyDecimals: 0,
// paymentFn(amount, annualRatePct, years, formula) -> monthly payment
// interestFn(amount, annualRatePct, years, formula) -> total interest
paymentFn: null,
interestFn: null
}
};
</script>
<script>
(function () {
var CFG = window.MortgageCalcConfig;
var CSS =
".tp-calc,.tp-calc *{box-sizing:border-box}" +
".tp-calc{--tp-card-bg:#f0f6fd;--tp-track-fill:#197bff;--tp-track-empty:rgba(17,17,17,0.05);--tp-thumb-bg:#fff;--tp-thumb-border:rgba(17,17,17,0.1);--tp-track-h:6px;--tp-thumb-size:24px;--tp-input-border:1px solid rgba(17,17,17,0.2);--tp-pill-min-width:84px;--tp-card-radius:22px;color:inherit}" +
".tp-calc__wrap{max-width:1180px;margin:40px auto;padding:0 24px;display:grid;grid-template-columns:1.1fr 0.9fr;gap:48px;align-items:start}" +
".tp-calc__h{margin:0}" +
".tp-calc__title{margin:0 0 32px}" +
".tp-calc__field{padding:6px 0}" +
".tp-calc__labelRow{display:flex;align-items:center;justify-content:space-between;gap:16px;margin-bottom:18px}" +
".tp-calc__sm{margin:14px 0 0}" +
".tp-calc__pill{min-width:var(--tp-pill-min-width);background:#fff;border:var(--tp-input-border);border-radius:12px;padding:12px 16px;display:inline-flex;gap:0;align-items:center;justify-content:center;font-size:17px;color:#111}" +
".tp-calc__num{width:auto;min-width:1ch;border:0;background:transparent;padding:0;margin:0;color:inherit}" +
".tp-calc__unit{margin-left:6px}" +
".tp-calc__unit--tight{margin-left:2px}" +
".tp-calc__range{width:100%;-webkit-appearance:none;appearance:none;height:var(--tp-track-h);border-radius:999px;margin:4px 0 0;cursor:pointer;background:linear-gradient(90deg,var(--tp-track-fill) 0%,var(--tp-track-fill) var(--tp-fill,0%),var(--tp-track-empty) var(--tp-fill,0%),var(--tp-track-empty) 100%)}" +
".tp-calc__range::-webkit-slider-thumb{-webkit-appearance:none;appearance:none;width:var(--tp-thumb-size);height:var(--tp-thumb-size);border-radius:50%;background:var(--tp-thumb-bg);border:1px solid var(--tp-thumb-border);box-shadow:0 2px 6px rgba(0,0,0,.15);cursor:pointer}" +
".tp-calc__range::-moz-range-thumb{width:var(--tp-thumb-size);height:var(--tp-thumb-size);border-radius:50%;background:var(--tp-thumb-bg);border:1px solid var(--tp-thumb-border);box-shadow:0 2px 6px rgba(0,0,0,.15);cursor:pointer}" +
".tp-calc__minmax{display:flex;justify-content:space-between;margin-top:12px}" +
".tp-calc__divider{height:1px;background:rgba(17,17,17,0.08);margin:30px 0}" +
".tp-calc__card{width:100%;background:var(--tp-card-bg);border-radius:var(--tp-card-radius);padding:44px}" +
".tp-calc__card .tp-calc__h{margin:0 0 4px}" +
".tp-calc__total{font-weight:800;font-size:60px;line-height:1;margin:10px 0 6px}" +
".tp-calc__cardDivider{height:1px;background:rgba(17,17,17,0.1);margin:28px 0}" +
".tp-calc__etaRow{display:flex;justify-content:space-between;align-items:flex-start;gap:16px}" +
".tp-calc__etaVal{font-size:20px;font-weight:700;white-space:nowrap}" +
".tp-calc__spacer{height:26px}" +
".tp-calc__spacer--lg{height:40px}" +
".tp-calc a.tp-calc__btn{display:block !important;width:100% !important;text-align:center !important;border-radius:10px !important;margin-top:20px}" +
"@media (max-width:980px){.tp-calc__wrap{grid-template-columns:1fr;gap:28px}.tp-calc__card{padding:34px}}" +
"@media (max-width:520px){.tp-calc__card{padding:28px}.tp-calc__total{font-size:52px}}";
function decl(prop, val) { return val ? prop + ":" + val + " !important;" : ""; }
function buttonCSS() {
var B = CFG.button;
var base = decl("color", B.text) + decl("background-color", B.bg) + decl("border-color", B.border);
var hover = decl("color", B.hoverText) + decl("background-color", B.hoverBg) + decl("border-color", B.hoverBorder);
var out = "";
if (base) out += ".tp-calc a.tp-calc__btn{" + base + "}";
if (hover) out += ".tp-calc a.tp-calc__btn:hover{" + hover + "}";
return out;
}
function injectCSS() {
if (window.__mortCalcStyled) return;
window.__mortCalcStyled = true;
var st = document.createElement("style");
st.type = "text/css";
st.textContent = CSS + buttonCSS();
document.head.appendChild(st);
}
function el(tag, cls, txt) {
var e = document.createElement(tag);
if (cls) e.className = cls;
if (txt != null) e.textContent = txt;
return e;
}
function heading(tag, txt, color) {
var e = el(tag, "tp-calc__h", txt);
if (color) e.style.color = color;
return e;
}
function smallP(txt, color) {
var e = el("p", "sqsrte-small tp-calc__sm", txt);
if (color) e.style.color = color;
return e;
}
function stepDecimals(step) {
var s = String(step);
var i = s.indexOf(".");
return i < 0 ? 0 : (s.length - i - 1);
}
function fmtNumber(v, decimals) {
return (+v).toLocaleString("en-US", { minimumFractionDigits: 0, maximumFractionDigits: decimals });
}
function formatMoney(n) {
var F = CFG.formula;
var d = Math.max(0, F.moneyDecimals | 0);
return F.currencySymbol + (+n).toLocaleString("en-US", { minimumFractionDigits: d, maximumFractionDigits: d });
}
function calcMonthly(P, ratePct, years) {
var F = CFG.formula;
if (typeof F.paymentFn === "function") return F.paymentFn(P, ratePct, years, F);
var r = (ratePct / 100) / 12;
var n = years * 12;
if (!n) return 0;
if (r === 0) return P / n;
var pow = Math.pow(1 + r, n);
return P * (r * pow) / (pow - 1);
}
function calcInterest(P, ratePct, years) {
var F = CFG.formula;
if (typeof F.interestFn === "function") return F.interestFn(P, ratePct, years, F);
return calcMonthly(P, ratePct, years) * years * 12 - P;
}
function clampNum(v, min, max, decimals) {
v = +v;
if (!isFinite(v)) v = min;
v = Math.min(max, Math.max(min, v));
var f = Math.pow(10, decimals || 0);
return Math.round(v * f) / f;
}
var measureSpan;
function autosize(input) {
if (!measureSpan) {
measureSpan = document.createElement("span");
measureSpan.style.cssText = "position:absolute;visibility:hidden;white-space:pre;left:-9999px;top:0";
document.body.appendChild(measureSpan);
}
var cs = window.getComputedStyle(input);
measureSpan.style.fontFamily = cs.fontFamily;
measureSpan.style.fontSize = cs.fontSize;
measureSpan.style.fontWeight = cs.fontWeight;
measureSpan.style.fontStyle = cs.fontStyle;
measureSpan.style.letterSpacing = cs.letterSpacing;
measureSpan.textContent = input.value || "0";
input.style.width = (measureSpan.offsetWidth + 2) + "px";
}
function numField(o) {
var decimals = stepDecimals(o.r.step);
var node = el("div", "tp-calc__field");
var row = el("div", "tp-calc__labelRow");
row.appendChild(heading(o.tag, o.label, CFG.colors.label));
var pill = el("div", "tp-calc__pill");
var input = el("input", "tp-calc__num");
input.type = "text";
input.setAttribute("inputmode", decimals ? "decimal" : "numeric");
input.setAttribute("aria-label", o.label);
pill.appendChild(input);
if (o.suffix) {
pill.appendChild(el("span", "tp-calc__unit" + (o.suffixTight ? " tp-calc__unit--tight" : ""), o.suffix));
}
row.appendChild(pill);
node.appendChild(row);
var range = el("input", "tp-calc__range");
range.type = "range";
range.min = o.r.min; range.max = o.r.max; range.step = o.r.step; range.value = o.r.value;
range.setAttribute("aria-label", o.label);
node.appendChild(range);
var mm = el("div", "tp-calc__minmax");
var s1 = el("span", "sqsrte-small", labelText(o.r.min));
var s2 = el("span", "sqsrte-small", labelText(o.r.max));
if (CFG.colors.smallText) { s1.style.color = CFG.colors.smallText; s2.style.color = CFG.colors.smallText; }
mm.appendChild(s1); mm.appendChild(s2);
node.appendChild(mm);
if (o.hint) node.appendChild(smallP(o.hint, CFG.colors.smallText));
function labelText(v) {
var s = (o.prefix || "") + fmtNumber(v, decimals);
if (o.suffix) s += (o.suffixTight ? "" : " ") + o.suffix;
return s;
}
function disp(v) { return (o.prefix || "") + fmtNumber(v, decimals); }
function get() {
var cleaned = (input.value || "").replace(/[^0-9.]/g, "");
var v = cleaned === "" ? o.r.min : parseFloat(cleaned);
return clampNum(v, o.r.min, o.r.max, decimals);
}
function fill() {
var v = +range.value, min = +range.min, max = +range.max;
range.style.setProperty("--tp-fill", ((v - min) / (max - min)) * 100 + "%");
}
function sync(v) { range.value = v; fill(); autosize(input); }
var cb = function () {};
input.addEventListener("input", function () { autosize(input); cb(); });
input.addEventListener("change", function () { input.value = disp(get()); autosize(input); cb(); });
range.addEventListener("input", function () { input.value = disp(+range.value); autosize(input); cb(); });
input.value = disp(o.r.value);
fill();
return { node: node, get: get, sync: sync, onChange: function (f) { cb = f; } };
}
function mount(root) {
if (!root || root.dataset.tpDone === "1") return;
root.dataset.tpDone = "1";
var T = CFG.text, G = CFG.tags, K = CFG.colors, S = CFG.slider, R = CFG.ranges, F = CFG.formula;
root.style.setProperty("--tp-card-bg", K.cardBg);
root.style.setProperty("--tp-track-fill", S.trackFill);
root.style.setProperty("--tp-track-empty", S.trackEmpty);
root.style.setProperty("--tp-thumb-bg", S.thumbBg);
root.style.setProperty("--tp-thumb-border", S.thumbBorder);
root.style.setProperty("--tp-track-h", S.trackHeight);
root.style.setProperty("--tp-thumb-size", S.thumbSize);
root.style.setProperty("--tp-input-border", CFG.layout.inputBorder);
var wrap = el("div", "tp-calc__wrap");
var left = el("div", "tp-calc__left");
var right = el("div", "tp-calc__right");
if (T.title) {
var title = heading(G.title, T.title, K.title);
title.classList.add("tp-calc__title");
left.appendChild(title);
}
var aField = numField({ label: T.amountLabel, tag: G.amountLabel, prefix: F.currencySymbol, hint: T.amountHint, r: R.amount });
left.appendChild(aField.node);
left.appendChild(el("div", "tp-calc__divider"));
var rField = numField({ label: T.rateLabel, tag: G.rateLabel, suffix: T.rateUnit, suffixTight: true, hint: T.rateHint, r: R.rate });
left.appendChild(rField.node);
left.appendChild(el("div", "tp-calc__divider"));
var pField = numField({ label: T.periodLabel, tag: G.periodLabel, suffix: T.periodUnit, hint: T.periodHint, r: R.period });
left.appendChild(pField.node);
var card = el("div", "tp-calc__card");
card.appendChild(heading(G.paymentHeading, T.paymentHeading, K.cardHeading));
var total = el("div", "tp-calc__total");
if (K.cardValue) total.style.color = K.cardValue;
card.appendChild(total);
card.appendChild(smallP(T.paymentHint, K.cardMuted));
card.appendChild(el("div", "tp-calc__cardDivider"));
var intRow = el("div", "tp-calc__etaRow");
var intLeft = el("div");
intLeft.appendChild(heading(G.interestLabel, T.interestLabel, K.cardHeading));
intLeft.appendChild(smallP(T.interestHint, K.cardMuted));
var intVal = el("div", "tp-calc__etaVal");
if (K.cardValue) intVal.style.color = K.cardValue;
intRow.appendChild(intLeft); intRow.appendChild(intVal);
card.appendChild(intRow);
card.appendChild(el("div", "tp-calc__spacer tp-calc__spacer--lg"));
card.appendChild(heading(G.ctaHeading, T.ctaHeading, K.cardHeading));
card.appendChild(smallP(T.ctaHint, K.cardMuted));
var btn = el("a", "btn btn--border theme-btn--primary-inverse sqs-button-element--primary tp-calc__btn", T.ctaButton);
btn.setAttribute("href", T.ctaHref);
btn.setAttribute("rel", "noopener");
card.appendChild(btn);
right.appendChild(card);
wrap.appendChild(left); wrap.appendChild(right);
root.appendChild(wrap);
function recalc() {
var P = aField.get(), rate = rField.get(), years = pField.get();
aField.sync(P); rField.sync(rate); pField.sync(years);
total.textContent = formatMoney(calcMonthly(P, rate, years));
intVal.textContent = formatMoney(calcInterest(P, rate, years));
}
aField.onChange(recalc);
rField.onChange(recalc);
pField.onChange(recalc);
recalc();
}
function init() {
var nodes = document.querySelectorAll("[data-tp-calc]");
for (var i = 0; i < nodes.length; i++) mount(nodes[i]);
}
function ready(fn) {
if (document.readyState !== "loading") fn();
else document.addEventListener("DOMContentLoaded", fn);
}
injectCSS();
ready(init);
if (!window.__mortCalcBound) {
window.__mortCalcBound = true;
window.addEventListener("mercury:load", init);
}
})();
</script>

#2. Customize
#2.1. To change text + button url, change line 06 – 24
text: {
title: "",
amountLabel: "Loan Amount",
amountHint: "Enter the total loan amount you want to borrow",
rateLabel: "Interest Rate",
rateUnit: "%",
rateHint: "",
periodLabel: "Loan Period",
periodUnit: "years",
periodHint: "",
paymentHeading: "Monthly Payment",
paymentHint: "This is an approximate monthly repayment amount for your mortgage based on the given inputs.",
interestLabel: "Total Interest Paid",
interestHint: "This is the total interest you would pay over the entire loan period.",
ctaHeading: "Ready to get started?",
ctaHint: "Get in touch with our mortgage advisors for personalized advice!",
ctaButton: "Book a Meeting",
ctaHref: "/contact-us"
},
#2.2. Style will inherit from Tags. You can set tags for all elements (title, description, paragraph, button..) here (line 25 – 33)
tags: {
title: "h2",
amountLabel: "h3",
rateLabel: "h3",
periodLabel: "h3",
paymentHeading: "h3",
interestLabel: "h3",
ctaHeading: "h2"
},
#2.3. To change color, change line 34 – 42
- Color will inherit from Tags. So if you use Heading 2 (h2), you can change Color in Site Styles
colors: {
title: "",
label: "",
smallText: "",
cardBg: "#f0f6fd",
cardHeading: "",
cardValue: "",
cardMuted: "rgba(17,17,17,0.6)"
},
#2.4. To change scroll/track bar style, change line 43 – 50
slider: {
trackFill: "#197bff",
trackEmpty: "rgba(17,17,17,0.05)",
thumbBg: "#ffffff",
thumbBorder: "rgba(17,17,17,0.1)",
trackHeight: "6px",
thumbSize: "24px"
},
#2.5. To change button style (it will inherit from Primary Button Style), you can change line 54 to line 61
button: {
text: "#ffffff",
bg: "#197bff",
border: "#197bff",
hoverText: "#ffffff",
hoverBg: "#1569e0",
hoverBorder: "#1569e0"
},
#2.6. To set Amount, Rate, Period, change line 62 – 66
ranges: {
amount: { min: 100000, max: 5000000, step: 10000, value: 1000000 },
rate: { min: 1, max: 15, step: 0.1, value: 5 },
period: { min: 5, max: 40, step: 1, value: 30 }
},
#2.7. To change formula, change line 67 – 74
formula: {
currencySymbol: "$",
moneyDecimals: 0,
// paymentFn(amount, annualRatePct, years, formula) -> monthly payment
// interestFn(amount, annualRatePct, years, formula) -> total interest
paymentFn: null,
interestFn: null
}
An example (If you don’t understand it, describe formula then send it to AI, AI will build it for you)
formula: {
currencySymbol: "$",
moneyDecimals: 0,
paymentFn: function (amount, rate, years, F) {
var totalInterest = amount * (rate / 100) * years;
return (amount + totalInterest) / (years * 12);
},
interestFn: function (amount, rate, years, F) {
return amount * (rate / 100) * years;
}
},