Skip to content

Components / Sections

Listing Gallery

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. The first picture can carry the view-transition-name its card on the listing page gave it, so the card grows into it.

Live demo

The Boathouse

Southbank, on the river path

$1,150,000 Guide price (a sample)

Bedrooms
4
Bathrooms
3
Floor area
204 m²
Built
2019

Book a viewing

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

Measured

JavaScript of its own

0 B

Uses Lens and the shared runtime (1.9 kB raw, once per site). With those included: 2.5 kB raw.

CSS 14.8 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 · newly available

Chrome 105 · Firefox 121 · Safari 15.4; needs has. Elsewhere: without :has() the first picture shows and the thumbnails do nothing.

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/listing-gallery
src/pages/index.astro
---
import ListingGallery from '@/components/moonarc/pro/ListingGallery.astro';
---
<ListingGallery
  title="12 Linden Row"
  address="Linden Hill, 10 minutes to the station"
  price="$845,000"
  priceNote="Guide price"
  facts={[{ label: 'Bedrooms', value: '4' }, { label: 'Bathrooms', value: '2' }, { label: 'Area', value: '142 m²' }, { label: 'Garden', value: 'South facing' }]}
  views={[
    { kind: 'house', seed: '12 Linden Row', block: 2, name: 'The front', label: 'The house from the street' },
    { kind: 'house', seed: '12 Linden Row', time: 'dusk', block: 2, name: 'At dusk', label: 'The house at dusk' },
  ]}
  primary={{ href: '#viewing', label: 'Book a viewing' }}
/>

Without a key the registry answers 401 with an upgrade message. Everything this section composes is free: home-art, lens.

Props

PropTypeDefaultDescription
titlestringnoneThe home's name or street, the page's heading.
pricestringnoneAs written.
views(HomeArt props & { label; name })[]noneOne to five pictures. label is what a screen reader hears; name is the thumbnail's.
addressstringnoneA line under the title.
priceNotestringnoneA word beside the price: "Guide price", "a month".
badgestringnoneA tag over the title.
facts{ label: string; value: string }[]noneThe facts, in two columns.
primary{ href: string; label: string }noneThe main action.
secondary{ href: string; label: string }noneThe second action.
transitionstringnoneThe view-transition-name of the first picture.
pickstring'Pictures'The thumbnails' group name.
level1 | 21Heading level of the title.
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.

Classes

.ma-home.ma-lgal.ma-lgal__actions.ma-lgal__address.ma-lgal__badge.ma-lgal__facts.ma-lgal__inner.ma-lgal__media.ma-lgal__mini.ma-lgal__note.ma-lgal__price.ma-lgal__primary.ma-lgal__radio.ma-lgal__secondary.ma-lgal__thumb.ma-lgal__thumbs.ma-lgal__title.ma-lgal__view.ma-lgal__views

Slots

none

Reduced motion

The thumbnails switch pictures at once; the lens appears without its fade.

With ClientRouter

CSS, and the Lens bound through the runtime.

Why it is built this way

Replaces: Listing page galleries built on a slider library. See the migration table.

Home Art

Backgrounds

A building drawn flat, for a listing that has no photograph yet: a house, a terrace, an apartment block, a villa, a cabin, a tower, an office or a shop, in the colour of the block or tone it sits on, with a shade, a light and the windows mixed from it.

every browserpointer

Lens

Pointer

A round magnifier that follows the pointer over a picture.

every browserpointerhover

Room by room

Point at a room in the list to find it on the plan.

Rooms · Ground floor

  • Living room22.5 m²
  • Kitchen18 m²
  • Hall7.5 m²
  • Dining room19.5 m²

Total67.5 m²

Rooms · First floor

  • Bedroom 118 m²
  • Bedroom 218 m²
  • Bathroom10.5 m²
  • Bedroom 312.3 m²
  • Landing8.8 m²

Total67.5 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.

newly · Chrome 105 · Firefox 121 · Safari 15.4pointerclick

Homes for sale

Pick a kind and the least bedrooms: the cards filter with no script. Sample homes and prices.

Kind
Bedrooms

6 homes6 homes5 homes3 homes2 homes3 homes3 homes3 homes3 homes2 homes3 homes3 homes2 homes0 homes0 homes

No home matches. Try fewer bedrooms or another kind.No home matches. Try fewer bedrooms or another kind.

Homes as cards (the building drawn by HomeArt, the price, the address, the beds, the baths and the area) with filters that work with no script: a group of radios for the kind of home and one for the least bedrooms, and :has() rules written for the list at build hide every card that does not match.

newly · Chrome 105 · Firefox 121 · Safari 15.4clickscroll

Also: view transitions · how costs are measured · browser support · accessibility policy · five-minute setup · MCP for agents · this page as Markdown