What a home costs a month. To buy: the price, the deposit on a slider, the rate and the term, and the monthly payment, the loan and the interest over the term. To rent: the deposit in months and the household's income, and the money to move in, the year's rent and the rent's share of the income. The first figures are worked out at build from the defaults and a few lines of script work out the rest as the fields change; without JavaScript the fields are not shown and a table worked out at build takes their place. An estimate, and it says so under itself.
Live demo
What it would cost a month
Each month
$3,796
Loan
$676,000
Interest over the term
$462,770
Monthly payment by deposit and term
Deposit
15 years
20 years
25 years
30 years
10%
$5,857
$4,852
$4,270
$3,899
20%
$5,206
$4,313
$3,796
$3,465
30%
$4,555
$3,774
$3,321
$3,032
An estimate to plan with. A lender works out the real figure.
Live, from the library itself, at full size: scroll, hover, navigate away and back. The demo is never gated.
Variants · each row writes the attribute the prop writes; the section's own CSS answers
tone
density
mode
Measured
JavaScript of its own
845 B raw
526 B gzip.
Uses Reveal and the shared runtime (1.9 kB raw, once per site). With those included: 3.8 kB raw.
CSS 10.4 kB raw including the base tokens. Measured from a production build, and again in CI for every change that can move it.
Browser support
Baseline · widely available
every browser. Elsewhere: without JavaScript a table of payments worked out at build.
Install Pro
The demo above is never gated; the source is. With a key in components.json (see account), the registry serves it like any other item:
terminal
npx shadcn@latest add @moonarc-pro/mortgage-calc
src/pages/index.astro
---import MortgageCalc from '@/components/moonarc/pro/MortgageCalc.astro';---<MortgageCalc headline="What it costs a month" amount={845000} deposit={20} rate={4.5} term={25}/>
Without a key the registry answers 401 with an upgrade message. Everything this section composes is free: reveal.
Props
Prop
Type
Default
Description
amount
number
none
The price (buy) or the monthly rent (rent), in whole units.
mode
'buy' | 'rent'
'buy'
A loan's monthly payment, or the money to move in and the rent's share of the income.
format
string
'{currency}{n}'
How a sum prints: {currency} is the currency, {n} the number.
currency
string
'$'
The currency's sign or code.
locale
string
'en-US'
How the numbers are grouped.
deposit
number
20
Buy: the deposit's share the slider starts at, in %.
rate
number
4.5
Buy: the yearly rate the field starts at, in %.
term
number
25
Buy: the term in years the field starts at.
terms
number[]
[15, 20, 25, 30]
Buy: the terms offered.
months
number[]
[1, 2, 3]
Rent: the deposits offered, in months.
income
number
6000
Rent: the household income a month the field starts at.
words
Partial<Record<…, string>>
English
Every word of the fields, the results, the table and the note.
headline
string
none
The heading.
eyebrow
string
none
A short line above the heading.
copy
string
none
A line under the heading.
level
2 | 3
2
Heading level of the heading.
tone
'surface' | 'muted' | 'ink' | 'brand'
unset (paints nothing)
The section's ground.
density
'compact' | 'cozy' | 'roomy'
'cozy'
Block padding ×0.8 / ×1 / ×1.25 through --ma-density.
Theming and overrides
The section reads the theme contract (shadcn's variable names with the base tokens as fallback), so a pasted theme or one --ma-brand recolours it. Its class names are the override surface and stay stable; a named slot replaces the matching prop with your own markup.
The figures on first paint are the build's, from the defaults, so the page reads right before the script runs and in a crawler.
The fields need the script, so they are shown only under the runtime's gate (html[data-ma-js]); without it a table of payments by deposit and term, worked out at build, takes their place.
The results sit in a polite live region, so a screen reader hears the new monthly figure after a change.
Replaces: Embedded mortgage calculator widgets from lenders. See the migration table.
Related
Room by room
Point at a room in the list to find it on the plan.
Living room22.5 m²Kitchen18 m²Hall7.5 m²Dining room19.5 m²
Rooms · Ground floor
Living room22.5 m²
Kitchen18 m²
Hall7.5 m²
Dining room19.5 m²
Total67.5 m²
Bedroom 118 m²Bedroom 218 m²Bathroom10.5 m²Bedroom 312.3 m²Landing8.8 m²
A home's floors drawn from its rooms: each room a rectangle on a grid of metres with its walls round it and its name and area over it, and beside the plan the same rooms as a list with the total.
The top of a home's own page: its pictures on one side, each a building drawn by HomeArt under a Lens that magnifies it at the pointer, with a row of thumbnails that picks one (radios and :has(), so the arrow keys move along them); on the other side the price, the title, the address, the facts and two actions.
Shows pricing plans side by side, with an annual/monthly toggle that rolls every price digit by digit to the other period with zero JavaScript (radios, :has and NumberFlow), the highlighted plan wearing a travelling border beam, cards revealed with a stagger.