webdevpuneet.com

Property Listing Card — Free Real Estate Card UI Snippet

Property Listing Card · Cards · Plain HTML, CSS & JS · Live preview

CategoryCards

Copy & paste

Source Code

<article class="plc-card" id="plcCard">
  <div class="plc-media">
    <span class="plc-badge" id="plcBadge">New</span>
    <button class="plc-fav" id="plcFav" type="button" aria-pressed="false" aria-label="Save property">
      <svg class="plc-heart" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
        <path d="M12 21s-7.5-4.6-10-9.2C.4 8.1 2 4.5 5.6 4c2.1-.3 4 .8 6.4 3.2C14.4 4.8 16.3 3.7 18.4 4c3.6.5 5.2 4.1 3.6 7.8C19.5 16.4 12 21 12 21z"></path>
      </svg>
    </button>
    <span class="plc-price">$625,000</span>
  </div>
  <div class="plc-body">
    <div class="plc-stats">
      <span class="plc-stat"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 18v-6a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2v6"></path><path d="M3 18h18M5 10V6a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v4M13 10V8a1 1 0 0 1 1-1h4a2 2 0 0 1 2 2v1"></path></svg>3 bd</span>
      <span class="plc-stat"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M4 12h16v3a3 3 0 0 1-3 3H7a3 3 0 0 1-3-3v-3z"></path><path d="M6 12V6a2 2 0 0 1 2-2h1M4 12V9a1 1 0 0 1 1-1h1M6 18v2M18 18v2"></path></svg>2 ba</span>
      <span class="plc-stat"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 3h7v7H3zM14 3h7v7h-7zM14 14h7v7h-7zM3 14h7v7H3z"></path></svg>1,840 sqft</span>
    </div>
    <h3 class="plc-address">428 Maple Ridge Court</h3>
    <p class="plc-sub">Willow Creek, TX 78660</p>
    <div class="plc-foot">
      <span class="plc-days">Listed 4 days ago</span>
      <span class="plc-agent">Listed by Rowan &amp; Co.</span>
    </div>
  </div>
</article>

Extend with AI

Take This Snippet Further With AI

The AI prompt for this one is for Patreon supporters ($3 a month), along with a site with no ads. Supporters enter the passcode once and it is remembered in this browser.

· Become a supporter

What's included

Features

CSS-only photo placeholder
A layered gradient and roofline silhouette — no image request needed.
Floating price tag
A high-contrast overlay pinned to the media area's corner.
Inline SVG stat icons
Bed, bath, and sqft icons with no icon-font dependency.
Accessible save toggle
Real button with aria-pressed and a dynamic aria-label.
Animated heart fill
Scales and fills color on save for instant visual feedback.
Status badge
New or Price reduced, color-coded and easy to restyle.
Fixed-ratio media
aspect-ratio keeps every card aligned in a responsive grid.
Grid-ready layout
Consistent footer height so rows stay level at any column count.

About this UI Snippet

Property Listing Card — Real Estate Photo, Stats, and Save Toggle in One Card

Screenshot of the Property Listing Card snippet rendered live

The property listing card is the unit every real-estate search result, map pin popup, and "similar homes" rail is built from — a photo, a price, the beds/baths/sqft trio, an address, and a way to shortlist it without leaving the grid. This snippet builds that card with a pure-CSS photo placeholder (a layered gradient with a faint window-and-roofline silhouette, no image request required), a floating price tag, a status badge, and an accessible heart toggle.

A CSS-only photo placeholder

Instead of a real photo, the media area layers a diagonal gradient, two repeating-linear-gradient textures for subtle grain, and a clipped polygon that reads as a simple roofline silhouette against the horizon. It's deliberately abstract — the point is to demonstrate the card's layout and states without depending on a licensed image — and it's trivial to swap for a real <img> or background photo in production.

Stats row with inline icon SVGs

Beds, baths, and square footage sit in a row of small inline SVG icons paired with bold numerals, the scannable pattern buyers pattern-match on instantly across every major listing site. Each icon is a tiny hand-drawn path (a bed frame, a tub, a floor-plan grid) rather than an icon-font dependency, keeping the snippet free of external requests — consistent with how a product card keeps its rating stars inline rather than font-based.

An accessible save toggle

The heart button is a real <button> with aria-pressed reflecting saved state and an aria-label that updates between "Save property" and "Remove from saved properties" — the same accessible toggle-button pattern used by favorite button and wishlist heart button. The heart fills and briefly scales up on save, giving immediate visual confirmation without a network round trip.

Status badge for urgency and updates

A top-left badge flags listing status — "New" in green for a fresh listing, or "Price reduced" in amber when the seller drops the price — the kind of contextual signal that drives clicks in a search results grid. In this demo, clicking the badge toggles between the two states so you can preview both without editing the markup.

Built for a grid, and for a calculator handoff

The card's fixed-ratio media and consistent footer height make it safe to repeat in a CSS grid of any column count. Once a buyer taps into a listing, the natural next step is affordability — hand the price straight into a mortgage calculator or the fuller mortgage payment breakdown so they can see a monthly payment before they ever contact an agent.

Step by step

How to Use

  1. 1
    Paste HTML, CSS, and JSA listing card renders with a gradient photo placeholder, price tag, badge, and stats row.
  2. 2
    Click the heartThe icon fills and scales up; aria-pressed and aria-label update for screen readers.
  3. 3
    Click the badgeToggles between "New" and "Price reduced" so you can preview both states.
  4. 4
    Swap in a real photoReplace the .plc-media gradient with a background-image or an <img>.
  5. 5
    Repeat it in a gridWrap several cards in a CSS grid — the fixed aspect-ratio keeps rows aligned.
  6. 6
    Wire up the click targetAdd a link or click handler on the card to open the full listing page.

Real-world uses

Common Use Cases

Real estate search results
Build the repeating unit of an MLS-style results list, with a price tag overlaid on a placeholder photo made from layered gradients.
Map pin popups
Use a compact version inside a map marker popup, with inline SVG icons for beds, baths and square footage.
Similar homes rails
Show a horizontal scroller of comparable listings in a similar homes rail, each with a New or Price reduced badge on the photo.
Saved favourites lists
Pair with a favorite button for a shortlist, with a real button using aria-pressed and a dynamic label.
Affordability hand-off
Link the price to a mortgage calculator, or showcase an agent's active listings on a portfolio page.

Got questions?

Frequently Asked Questions

So the snippet renders instantly with zero network requests and no licensing concerns while you evaluate the layout. In production, swap the .plc-media background for a real photo via background-image or an absolutely positioned <img> with object-fit: cover — the badge, price tag, and heart button are already positioned with z-index above the media layer, so they'll sit correctly on top of a real photo too.

It's a real <button>, not a styled <div>, so it's keyboard-focusable and clickable via Enter or Space by default. Its aria-pressed attribute reflects saved state as a boolean, and its aria-label switches between "Save property" and "Remove from saved properties" on toggle, so a screen reader announces both the current state and the action the next press will take.

Wrap the .plc-card in an <a> tag, or add a click handler on the card that navigates — but keep the heart button's click handler calling event.stopPropagation() so saving a listing doesn't also trigger navigation. That's the same pattern used by any card with a nested interactive control, like a product card with an add-to-cart button.

The badge is just a span with a modifier class (.reduced) that swaps its background color. Add more modifier classes — for example .pending or .open-house — each with its own background, and set the class and text based on the listing's actual status field when you render the card from data.

Pass address, price, stats, photo URL, and a saved boolean as props; render the heart button's aria-pressed and fill class from that boolean and toggle it in a click handler. In React, that's useState(false) with an onClick that flips it and calls a save callback; in Vue, a reactive ref bound with :aria-pressed and @click. The CSS ports unchanged.