bêta
Mosaic Gallery <mv-mosaic>
Mosaïque d’images qui se réorganise d’elle-même : la photo choisie devient la grande vignette et chaque vignette se transforme jusqu’à sa nouvelle place en une seule View Transition, recadrée plutôt qu’étirée. Variante rail : une bande de panneaux où celui qui est survolé ou qui a le focus s’élargit, ses voisins cèdent un peu de place et les autres rétrécissent.
Catégorie Médias Type Web Component (<mv-mosaic>) Statut bêta Keywords gallery, mosaic, grid, view-transition, layout-animation, rail, accordion, images, expand, keyboard
When to use
An editorial or portfolio grid should enlarge the chosen photo and glide the others to new spots A horizontal strip of image panels should widen the hovered or focused one, like an accordion Projects, destinations or team photos need their captions featured in the active tile
Avoid when
Product views need thumbnails, zoom and fullscreen → use Product Gallery instead The collection has dozens of images; the rearranging motion works best with a small set of tiles
Obtenir Mosaic Gallery. Inclus dans toutes les offres : le Pro pack contient les 317 composants, avec la CLI et le serveur MCP utilisés ci-dessous.
Voir les offres
Installation
node scripts/add.mjs mosaic-gallery --out ./src/marvelous
Agent IA avec le serveur MCP de Marvelous UI : install_components({ slugs: ["mosaic-gallery"], target_dir: "<absolute path>/src/marvelous", framework: "react" }).
Fichiers copiés (dépendances comprises) : tokens/tokens.css, core/base.css, core/dom.js, core/element.js, core/focus.js, core/motion.js, components/mosaic-gallery/mosaic-gallery.js, components/mosaic-gallery/mosaic-gallery.css.
Utilisation
Balisage de référence : partez de celui-ci et personnalisez-le avec les attributs, data-* et les variables CSS :
<div id="mv-mosaic-demo">
<style>
#mv-mosaic-demo { display: grid; gap: 2.25rem; width: 100%; max-width: 52rem; }
#mv-mosaic-demo section { display: grid; gap: .75rem; }
#mv-mosaic-demo header { display: flex; justify-content: space-between; align-items: baseline; gap: 1rem; flex-wrap: wrap; }
#mv-mosaic-demo header strong { font-size: .9375rem; }
#mv-mosaic-demo header small { color: var(--mv-fg-subtle); }
</style>
<section>
<header><strong>Selected projects</strong><small>Click or press Enter on a project to feature it</small></header>
<mv-mosaic label="Selected projects" style="--mv-mosaic-columns: 3; --mv-mosaic-row: 8.5rem">
<figure data-active><img src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 800 600' preserveAspectRatio='xMidYMid slice'%3E%3Cdefs%3E%3ClinearGradient id='k' x1='0' y1='0' x2='0' y2='1'%3E%3Cstop offset='0' stop-color='%231b1f4b'/%3E%3Cstop offset='.6' stop-color='%235b4b9a'/%3E%3Cstop offset='1' stop-color='%23f2a37c'/%3E%3C/linearGradient%3E%3Cpattern id='w' width='36' height='44' patternUnits='userSpaceOnUse'%3E%3Crect x='8' y='10' width='8' height='11' fill='%23ffcf8a' opacity='.8'/%3E%3Crect x='22' y='32' width='8' height='11' fill='%23ffcf8a' opacity='.45'/%3E%3C/pattern%3E%3CradialGradient id='h'%3E%3Cstop offset='0' stop-color='%23ffd9a8' stop-opacity='.85'/%3E%3Cstop offset='1' stop-color='%23ffd9a8' stop-opacity='0'/%3E%3C/radialGradient%3E%3C/defs%3E%3Crect width='800' height='600' fill='url(%23k)'/%3E%3Ccircle cx='610' cy='300' r='190' fill='url(%23h)'/%3E%3Ccircle cx='610' cy='300' r='54' fill='%23ffd9a8'/%3E%3Cg fill='%232a2a5c' opacity='.9'%3E%3Crect x='0' y='233' width='40' height='367'/%3E%3Crect x='44' y='354' width='60' height='246'/%3E%3Crect x='108' y='299' width='91' height='301'/%3E%3Crect x='203' y='262' width='63' height='338'/%3E%3Crect x='270' y='298' width='93' height='302'/%3E%3Crect x='367' y='282' width='88' height='318'/%3E%3Crect x='459' y='349' width='97' height='251'/%3E%3Crect x='560' y='270' width='66' height='330'/%3E%3Crect x='630' y='381' width='89' height='219'/%3E%3Crect x='723' y='310' width='88' height='290'/%3E%3C/g%3E%3Cg fill='%23141633'%3E%3Crect x='-10' y='264' width='153' height='336'/%3E%3Crect x='153' y='332' width='81' height='268'/%3E%3Crect x='244' y='292' width='153' height='308'/%3E%3Crect x='407' y='317' width='128' height='283'/%3E%3Crect x='545' y='241' width='152' height='359'/%3E%3Crect x='707' y='373' width='104' height='227'/%3E%3C/g%3E%3Cg fill='url(%23w)'%3E%3Crect x='-10' y='264' width='153' height='336'/%3E%3Crect x='153' y='332' width='81' height='268'/%3E%3Crect x='244' y='292' width='153' height='308'/%3E%3Crect x='407' y='317' width='128' height='283'/%3E%3Crect x='545' y='241' width='152' height='359'/%3E%3Crect x='707' y='373' width='104' height='227'/%3E%3C/g%3E%3C/svg%3E" alt="Library with glowing windows at dusk"><figcaption><strong>Harbor Library, Oslo</strong><span>Timber reading rooms over the fjord</span></figcaption></figure>
<figure><img src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 800 600' preserveAspectRatio='xMidYMid slice'%3E%3Cdefs%3E%3ClinearGradient id='k' x1='0' y1='0' x2='0' y2='1'%3E%3Cstop offset='0' stop-color='%230c3b4a'/%3E%3Cstop offset='.6' stop-color='%232f8f9d'/%3E%3Cstop offset='1' stop-color='%23c7ecea'/%3E%3C/linearGradient%3E%3Cpattern id='w' width='36' height='44' patternUnits='userSpaceOnUse'%3E%3Crect x='8' y='10' width='8' height='11' fill='%23e8fffb' opacity='.8'/%3E%3Crect x='22' y='32' width='8' height='11' fill='%23e8fffb' opacity='.45'/%3E%3C/pattern%3E%3CradialGradient id='h'%3E%3Cstop offset='0' stop-color='%23f4fffd' stop-opacity='.85'/%3E%3Cstop offset='1' stop-color='%23f4fffd' stop-opacity='0'/%3E%3C/radialGradient%3E%3C/defs%3E%3Crect width='800' height='600' fill='url(%23k)'/%3E%3Ccircle cx='190' cy='170' r='190' fill='url(%23h)'/%3E%3Ccircle cx='190' cy='170' r='54' fill='%23f4fffd'/%3E%3Cg fill='%2319525e' opacity='.9'%3E%3Crect x='0' y='334' width='99' height='266'/%3E%3Crect x='103' y='339' width='51' height='261'/%3E%3Crect x='157' y='340' width='70' height='260'/%3E%3Crect x='231' y='295' width='106' height='305'/%3E%3Crect x='341' y='241' width='91' height='359'/%3E%3Crect x='436' y='344' width='44' height='256'/%3E%3Crect x='484' y='304' width='79' height='296'/%3E%3Crect x='567' y='357' width='70' height='243'/%3E%3Crect x='641' y='381' width='104' height='219'/%3E%3Crect x='748' y='331' width='66' height='269'/%3E%3C/g%3E%3Cg fill='%230b2a33'%3E%3Crect x='-10' y='237' width='130' height='363'/%3E%3Crect x='130' y='412' width='116' height='188'/%3E%3Crect x='256' y='385' width='107' height='215'/%3E%3Crect x='373' y='352' width='103' height='248'/%3E%3Crect x='485' y='328' width='100' height='272'/%3E%3Crect x='595' y='396' width='125' height='204'/%3E%3Crect x='731' y='345' width='152' height='255'/%3E%3C/g%3E%3Cg fill='url(%23w)'%3E%3Crect x='-10' y='237' width='130' height='363'/%3E%3Crect x='130' y='412' width='116' height='188'/%3E%3Crect x='256' y='385' width='107' height='215'/%3E%3Crect x='373' y='352' width='103' height='248'/%3E%3Crect x='485' y='328' width='100' height='272'/%3E%3Crect x='595' y='396' width='125' height='204'/%3E%3Crect x='731' y='345' width='152' height='255'/%3E%3C/g%3E%3C/svg%3E" alt="Apartment towers in teal evening light"><figcaption><strong>Tide House, Lisbon</strong><span>Six floors of shared housing by the river</span></figcaption></figure>
<figure><img src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 800 600' preserveAspectRatio='xMidYMid slice'%3E%3Cdefs%3E%3ClinearGradient id='k' x1='0' y1='0' x2='0' y2='1'%3E%3Cstop offset='0' stop-color='%233a1631'/%3E%3Cstop offset='.6' stop-color='%23b04a5a'/%3E%3Cstop offset='1' stop-color='%23f7c59f'/%3E%3C/linearGradient%3E%3Cpattern id='w' width='36' height='44' patternUnits='userSpaceOnUse'%3E%3Crect x='8' y='10' width='8' height='11' fill='%23ffe0a3' opacity='.8'/%3E%3Crect x='22' y='32' width='8' height='11' fill='%23ffe0a3' opacity='.45'/%3E%3C/pattern%3E%3CradialGradient id='h'%3E%3Cstop offset='0' stop-color='%23fff0d6' stop-opacity='.85'/%3E%3Cstop offset='1' stop-color='%23fff0d6' stop-opacity='0'/%3E%3C/radialGradient%3E%3C/defs%3E%3Crect width='800' height='600' fill='url(%23k)'/%3E%3Ccircle cx='420' cy='340' r='190' fill='url(%23h)'/%3E%3Ccircle cx='420' cy='340' r='54' fill='%23fff0d6'/%3E%3Cg fill='%235e2440' opacity='.9'%3E%3Crect x='0' y='282' width='100' height='318'/%3E%3Crect x='104' y='302' width='84' height='298'/%3E%3Crect x='193' y='273' width='75' height='327'/%3E%3Crect x='272' y='323' width='106' height='277'/%3E%3Crect x='382' y='347' width='90' height='253'/%3E%3Crect x='476' y='330' width='81' height='270'/%3E%3Crect x='561' y='323' width='63' height='277'/%3E%3Crect x='628' y='241' width='96' height='359'/%3E%3Crect x='727' y='251' width='48' height='349'/%3E%3Crect x='779' y='321' width='45' height='279'/%3E%3C/g%3E%3Cg fill='%2324101f'%3E%3Crect x='-10' y='432' width='84' height='168'/%3E%3Crect x='84' y='399' width='160' height='201'/%3E%3Crect x='253' y='417' width='127' height='183'/%3E%3Crect x='390' y='314' width='111' height='286'/%3E%3Crect x='512' y='238' width='82' height='362'/%3E%3Crect x='604' y='245' width='150' height='355'/%3E%3Crect x='764' y='241' width='150' height='359'/%3E%3C/g%3E%3Cg fill='url(%23w)'%3E%3Crect x='-10' y='432' width='84' height='168'/%3E%3Crect x='84' y='399' width='160' height='201'/%3E%3Crect x='253' y='417' width='127' height='183'/%3E%3Crect x='390' y='314' width='111' height='286'/%3E%3Crect x='512' y='238' width='82' height='362'/%3E%3Crect x='604' y='245' width='150' height='355'/%3E%3Crect x='764' y='241' width='150' height='359'/%3E%3C/g%3E%3C/svg%3E" alt="Market halls in a pink sunset"><figcaption><strong>Rose Market, Marrakech</strong><span>A covered market for 140 stalls</span></figcaption></figure>
<figure><img src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 800 600' preserveAspectRatio='xMidYMid slice'%3E%3Cdefs%3E%3ClinearGradient id='k' x1='0' y1='0' x2='0' y2='1'%3E%3Cstop offset='0' stop-color='%2310233f'/%3E%3Cstop offset='.6' stop-color='%23355c8c'/%3E%3Cstop offset='1' stop-color='%239ec1e6'/%3E%3C/linearGradient%3E%3Cpattern id='w' width='36' height='44' patternUnits='userSpaceOnUse'%3E%3Crect x='8' y='10' width='8' height='11' fill='%23bfe0ff' opacity='.8'/%3E%3Crect x='22' y='32' width='8' height='11' fill='%23bfe0ff' opacity='.45'/%3E%3C/pattern%3E%3CradialGradient id='h'%3E%3Cstop offset='0' stop-color='%23eaf4ff' stop-opacity='.85'/%3E%3Cstop offset='1' stop-color='%23eaf4ff' stop-opacity='0'/%3E%3C/radialGradient%3E%3C/defs%3E%3Crect width='800' height='600' fill='url(%23k)'/%3E%3Ccircle cx='640' cy='150' r='190' fill='url(%23h)'/%3E%3Ccircle cx='640' cy='150' r='54' fill='%23eaf4ff'/%3E%3Cg fill='%231d3657' opacity='.9'%3E%3Crect x='0' y='343' width='93' height='257'/%3E%3Crect x='97' y='348' width='41' height='252'/%3E%3Crect x='142' y='390' width='45' height='210'/%3E%3Crect x='191' y='351' width='83' height='249'/%3E%3Crect x='279' y='307' width='92' height='293'/%3E%3Crect x='374' y='350' width='88' height='250'/%3E%3Crect x='467' y='350' width='102' height='250'/%3E%3Crect x='572' y='238' width='66' height='362'/%3E%3Crect x='642' y='307' width='48' height='293'/%3E%3Crect x='695' y='235' width='40' height='365'/%3E%3Crect x='739' y='233' width='85' height='367'/%3E%3C/g%3E%3Cg fill='%230a1629'%3E%3Crect x='-10' y='243' width='72' height='357'/%3E%3Crect x='72' y='227' width='87' height='373'/%3E%3Crect x='169' y='294' width='121' height='306'/%3E%3Crect x='300' y='399' width='94' height='201'/%3E%3Crect x='404' y='320' width='89' height='280'/%3E%3Crect x='502' y='273' width='75' height='327'/%3E%3Crect x='587' y='286' width='133' height='314'/%3E%3Crect x='730' y='442' width='115' height='158'/%3E%3C/g%3E%3Cg fill='url(%23w)'%3E%3Crect x='-10' y='243' width='72' height='357'/%3E%3Crect x='72' y='227' width='87' height='373'/%3E%3Crect x='169' y='294' width='121' height='306'/%3E%3Crect x='300' y='399' width='94' height='201'/%3E%3Crect x='404' y='320' width='89' height='280'/%3E%3Crect x='502' y='273' width='75' height='327'/%3E%3Crect x='587' y='286' width='133' height='314'/%3E%3Crect x='730' y='442' width='115' height='158'/%3E%3C/g%3E%3C/svg%3E" alt="Office towers under a pale blue sky"><figcaption><strong>North Pier Offices, Toronto</strong><span>Offices wrapped in cold-rolled glass</span></figcaption></figure>
<figure><img src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 800 600' preserveAspectRatio='xMidYMid slice'%3E%3Cdefs%3E%3ClinearGradient id='k' x1='0' y1='0' x2='0' y2='1'%3E%3Cstop offset='0' stop-color='%232b2410'/%3E%3Cstop offset='.6' stop-color='%238c6a2f'/%3E%3Cstop offset='1' stop-color='%23f3d58a'/%3E%3C/linearGradient%3E%3Cpattern id='w' width='36' height='44' patternUnits='userSpaceOnUse'%3E%3Crect x='8' y='10' width='8' height='11' fill='%23ffe6a0' opacity='.8'/%3E%3Crect x='22' y='32' width='8' height='11' fill='%23ffe6a0' opacity='.45'/%3E%3C/pattern%3E%3CradialGradient id='h'%3E%3Cstop offset='0' stop-color='%23fff5d1' stop-opacity='.85'/%3E%3Cstop offset='1' stop-color='%23fff5d1' stop-opacity='0'/%3E%3C/radialGradient%3E%3C/defs%3E%3Crect width='800' height='600' fill='url(%23k)'/%3E%3Ccircle cx='260' cy='280' r='190' fill='url(%23h)'/%3E%3Ccircle cx='260' cy='280' r='54' fill='%23fff5d1'/%3E%3Cg fill='%234a3a17' opacity='.9'%3E%3Crect x='0' y='234' width='48' height='366'/%3E%3Crect x='52' y='273' width='49' height='327'/%3E%3Crect x='105' y='384' width='103' height='216'/%3E%3Crect x='211' y='244' width='102' height='356'/%3E%3Crect x='317' y='228' width='109' height='372'/%3E%3Crect x='431' y='319' width='94' height='281'/%3E%3Crect x='528' y='266' width='57' height='334'/%3E%3Crect x='590' y='322' width='102' height='278'/%3E%3Crect x='695' y='321' width='56' height='279'/%3E%3Crect x='756' y='295' width='102' height='305'/%3E%3C/g%3E%3Cg fill='%231c170a'%3E%3Crect x='-10' y='307' width='102' height='293'/%3E%3Crect x='102' y='373' width='136' height='227'/%3E%3Crect x='248' y='353' width='135' height='247'/%3E%3Crect x='393' y='378' width='88' height='222'/%3E%3Crect x='491' y='221' width='159' height='379'/%3E%3Crect x='660' y='249' width='127' height='351'/%3E%3Crect x='797' y='404' width='153' height='196'/%3E%3C/g%3E%3Cg fill='url(%23w)'%3E%3Crect x='-10' y='307' width='102' height='293'/%3E%3Crect x='102' y='373' width='136' height='227'/%3E%3Crect x='248' y='353' width='135' height='247'/%3E%3Crect x='393' y='378' width='88' height='222'/%3E%3Crect x='491' y='221' width='159' height='379'/%3E%3Crect x='660' y='249' width='127' height='351'/%3E%3Crect x='797' y='404' width='153' height='196'/%3E%3C/g%3E%3C/svg%3E" alt="Hotel blocks in golden desert light"><figcaption><strong>Sand Court, Dubai</strong><span>Courtyard hotel with shaded terraces</span></figcaption></figure>
<figure><img src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 800 600' preserveAspectRatio='xMidYMid slice'%3E%3Cdefs%3E%3ClinearGradient id='k' x1='0' y1='0' x2='0' y2='1'%3E%3Cstop offset='0' stop-color='%231f1236'/%3E%3Cstop offset='.6' stop-color='%236a3d8f'/%3E%3Cstop offset='1' stop-color='%23e7a6c8'/%3E%3C/linearGradient%3E%3Cpattern id='w' width='36' height='44' patternUnits='userSpaceOnUse'%3E%3Crect x='8' y='10' width='8' height='11' fill='%23ffd1ea' opacity='.8'/%3E%3Crect x='22' y='32' width='8' height='11' fill='%23ffd1ea' opacity='.45'/%3E%3C/pattern%3E%3CradialGradient id='h'%3E%3Cstop offset='0' stop-color='%23ffe3f2' stop-opacity='.85'/%3E%3Cstop offset='1' stop-color='%23ffe3f2' stop-opacity='0'/%3E%3C/radialGradient%3E%3C/defs%3E%3Crect width='800' height='600' fill='url(%23k)'/%3E%3Ccircle cx='540' cy='220' r='190' fill='url(%23h)'/%3E%3Ccircle cx='540' cy='220' r='54' fill='%23ffe3f2'/%3E%3Cg fill='%233a2257' opacity='.9'%3E%3Crect x='0' y='367' width='85' height='233'/%3E%3Crect x='89' y='295' width='75' height='305'/%3E%3Crect x='168' y='229' width='94' height='371'/%3E%3Crect x='266' y='358' width='74' height='242'/%3E%3Crect x='344' y='362' width='71' height='238'/%3E%3Crect x='419' y='301' width='86' height='299'/%3E%3Crect x='509' y='304' width='79' height='296'/%3E%3Crect x='593' y='328' width='93' height='272'/%3E%3Crect x='690' y='386' width='93' height='214'/%3E%3Crect x='786' y='298' width='61' height='302'/%3E%3C/g%3E%3Cg fill='%23140b24'%3E%3Crect x='-10' y='284' width='88' height='316'/%3E%3Crect x='88' y='396' width='96' height='204'/%3E%3Crect x='194' y='351' width='129' height='249'/%3E%3Crect x='334' y='272' width='77' height='328'/%3E%3Crect x='421' y='239' width='144' height='361'/%3E%3Crect x='575' y='293' width='152' height='307'/%3E%3Crect x='737' y='444' width='156' height='156'/%3E%3C/g%3E%3Cg fill='url(%23w)'%3E%3Crect x='-10' y='284' width='88' height='316'/%3E%3Crect x='88' y='396' width='96' height='204'/%3E%3Crect x='194' y='351' width='129' height='249'/%3E%3Crect x='334' y='272' width='77' height='328'/%3E%3Crect x='421' y='239' width='144' height='361'/%3E%3Crect x='575' y='293' width='152' height='307'/%3E%3Crect x='737' y='444' width='156' height='156'/%3E%3C/g%3E%3C/svg%3E" alt="School buildings under a violet sky"><figcaption><strong>Lantern School, Seoul</strong><span>A primary school lit from within</span></figcaption></figure>
</mv-mosaic>
</section>
<section>
<header><strong>Studios</strong><small>variant="rail": hover, focus or use the arrow keys</small></header>
<mv-mosaic variant="rail" label="Studios" style="--mv-mosaic-rail-height: 16rem">
<figure><img src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 800 600' preserveAspectRatio='xMidYMid slice'%3E%3Cdefs%3E%3ClinearGradient id='k' x1='0' y1='0' x2='0' y2='1'%3E%3Cstop offset='0' stop-color='%2310233f'/%3E%3Cstop offset='.6' stop-color='%23355c8c'/%3E%3Cstop offset='1' stop-color='%239ec1e6'/%3E%3C/linearGradient%3E%3Cpattern id='w' width='36' height='44' patternUnits='userSpaceOnUse'%3E%3Crect x='8' y='10' width='8' height='11' fill='%23bfe0ff' opacity='.8'/%3E%3Crect x='22' y='32' width='8' height='11' fill='%23bfe0ff' opacity='.45'/%3E%3C/pattern%3E%3CradialGradient id='h'%3E%3Cstop offset='0' stop-color='%23eaf4ff' stop-opacity='.85'/%3E%3Cstop offset='1' stop-color='%23eaf4ff' stop-opacity='0'/%3E%3C/radialGradient%3E%3C/defs%3E%3Crect width='800' height='600' fill='url(%23k)'/%3E%3Ccircle cx='640' cy='150' r='190' fill='url(%23h)'/%3E%3Ccircle cx='640' cy='150' r='54' fill='%23eaf4ff'/%3E%3Cg fill='%231d3657' opacity='.9'%3E%3Crect x='0' y='343' width='93' height='257'/%3E%3Crect x='97' y='348' width='41' height='252'/%3E%3Crect x='142' y='390' width='45' height='210'/%3E%3Crect x='191' y='351' width='83' height='249'/%3E%3Crect x='279' y='307' width='92' height='293'/%3E%3Crect x='374' y='350' width='88' height='250'/%3E%3Crect x='467' y='350' width='102' height='250'/%3E%3Crect x='572' y='238' width='66' height='362'/%3E%3Crect x='642' y='307' width='48' height='293'/%3E%3Crect x='695' y='235' width='40' height='365'/%3E%3Crect x='739' y='233' width='85' height='367'/%3E%3C/g%3E%3Cg fill='%230a1629'%3E%3Crect x='-10' y='243' width='72' height='357'/%3E%3Crect x='72' y='227' width='87' height='373'/%3E%3Crect x='169' y='294' width='121' height='306'/%3E%3Crect x='300' y='399' width='94' height='201'/%3E%3Crect x='404' y='320' width='89' height='280'/%3E%3Crect x='502' y='273' width='75' height='327'/%3E%3Crect x='587' y='286' width='133' height='314'/%3E%3Crect x='730' y='442' width='115' height='158'/%3E%3C/g%3E%3Cg fill='url(%23w)'%3E%3Crect x='-10' y='243' width='72' height='357'/%3E%3Crect x='72' y='227' width='87' height='373'/%3E%3Crect x='169' y='294' width='121' height='306'/%3E%3Crect x='300' y='399' width='94' height='201'/%3E%3Crect x='404' y='320' width='89' height='280'/%3E%3Crect x='502' y='273' width='75' height='327'/%3E%3Crect x='587' y='286' width='133' height='314'/%3E%3Crect x='730' y='442' width='115' height='158'/%3E%3C/g%3E%3C/svg%3E" alt="Office towers under a pale blue sky"><figcaption><strong>North Pier Offices, Toronto</strong><span>Offices wrapped in cold-rolled glass</span></figcaption></figure>
<figure data-active><img src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 800 600' preserveAspectRatio='xMidYMid slice'%3E%3Cdefs%3E%3ClinearGradient id='k' x1='0' y1='0' x2='0' y2='1'%3E%3Cstop offset='0' stop-color='%230c3b4a'/%3E%3Cstop offset='.6' stop-color='%232f8f9d'/%3E%3Cstop offset='1' stop-color='%23c7ecea'/%3E%3C/linearGradient%3E%3Cpattern id='w' width='36' height='44' patternUnits='userSpaceOnUse'%3E%3Crect x='8' y='10' width='8' height='11' fill='%23e8fffb' opacity='.8'/%3E%3Crect x='22' y='32' width='8' height='11' fill='%23e8fffb' opacity='.45'/%3E%3C/pattern%3E%3CradialGradient id='h'%3E%3Cstop offset='0' stop-color='%23f4fffd' stop-opacity='.85'/%3E%3Cstop offset='1' stop-color='%23f4fffd' stop-opacity='0'/%3E%3C/radialGradient%3E%3C/defs%3E%3Crect width='800' height='600' fill='url(%23k)'/%3E%3Ccircle cx='190' cy='170' r='190' fill='url(%23h)'/%3E%3Ccircle cx='190' cy='170' r='54' fill='%23f4fffd'/%3E%3Cg fill='%2319525e' opacity='.9'%3E%3Crect x='0' y='334' width='99' height='266'/%3E%3Crect x='103' y='339' width='51' height='261'/%3E%3Crect x='157' y='340' width='70' height='260'/%3E%3Crect x='231' y='295' width='106' height='305'/%3E%3Crect x='341' y='241' width='91' height='359'/%3E%3Crect x='436' y='344' width='44' height='256'/%3E%3Crect x='484' y='304' width='79' height='296'/%3E%3Crect x='567' y='357' width='70' height='243'/%3E%3Crect x='641' y='381' width='104' height='219'/%3E%3Crect x='748' y='331' width='66' height='269'/%3E%3C/g%3E%3Cg fill='%230b2a33'%3E%3Crect x='-10' y='237' width='130' height='363'/%3E%3Crect x='130' y='412' width='116' height='188'/%3E%3Crect x='256' y='385' width='107' height='215'/%3E%3Crect x='373' y='352' width='103' height='248'/%3E%3Crect x='485' y='328' width='100' height='272'/%3E%3Crect x='595' y='396' width='125' height='204'/%3E%3Crect x='731' y='345' width='152' height='255'/%3E%3C/g%3E%3Cg fill='url(%23w)'%3E%3Crect x='-10' y='237' width='130' height='363'/%3E%3Crect x='130' y='412' width='116' height='188'/%3E%3Crect x='256' y='385' width='107' height='215'/%3E%3Crect x='373' y='352' width='103' height='248'/%3E%3Crect x='485' y='328' width='100' height='272'/%3E%3Crect x='595' y='396' width='125' height='204'/%3E%3Crect x='731' y='345' width='152' height='255'/%3E%3C/g%3E%3C/svg%3E" alt="Apartment towers in teal evening light"><figcaption><strong>Tide House, Lisbon</strong><span>Six floors of shared housing by the river</span></figcaption></figure>
<figure><img src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 800 600' preserveAspectRatio='xMidYMid slice'%3E%3Cdefs%3E%3ClinearGradient id='k' x1='0' y1='0' x2='0' y2='1'%3E%3Cstop offset='0' stop-color='%231f1236'/%3E%3Cstop offset='.6' stop-color='%236a3d8f'/%3E%3Cstop offset='1' stop-color='%23e7a6c8'/%3E%3C/linearGradient%3E%3Cpattern id='w' width='36' height='44' patternUnits='userSpaceOnUse'%3E%3Crect x='8' y='10' width='8' height='11' fill='%23ffd1ea' opacity='.8'/%3E%3Crect x='22' y='32' width='8' height='11' fill='%23ffd1ea' opacity='.45'/%3E%3C/pattern%3E%3CradialGradient id='h'%3E%3Cstop offset='0' stop-color='%23ffe3f2' stop-opacity='.85'/%3E%3Cstop offset='1' stop-color='%23ffe3f2' stop-opacity='0'/%3E%3C/radialGradient%3E%3C/defs%3E%3Crect width='800' height='600' fill='url(%23k)'/%3E%3Ccircle cx='540' cy='220' r='190' fill='url(%23h)'/%3E%3Ccircle cx='540' cy='220' r='54' fill='%23ffe3f2'/%3E%3Cg fill='%233a2257' opacity='.9'%3E%3Crect x='0' y='367' width='85' height='233'/%3E%3Crect x='89' y='295' width='75' height='305'/%3E%3Crect x='168' y='229' width='94' height='371'/%3E%3Crect x='266' y='358' width='74' height='242'/%3E%3Crect x='344' y='362' width='71' height='238'/%3E%3Crect x='419' y='301' width='86' height='299'/%3E%3Crect x='509' y='304' width='79' height='296'/%3E%3Crect x='593' y='328' width='93' height='272'/%3E%3Crect x='690' y='386' width='93' height='214'/%3E%3Crect x='786' y='298' width='61' height='302'/%3E%3C/g%3E%3Cg fill='%23140b24'%3E%3Crect x='-10' y='284' width='88' height='316'/%3E%3Crect x='88' y='396' width='96' height='204'/%3E%3Crect x='194' y='351' width='129' height='249'/%3E%3Crect x='334' y='272' width='77' height='328'/%3E%3Crect x='421' y='239' width='144' height='361'/%3E%3Crect x='575' y='293' width='152' height='307'/%3E%3Crect x='737' y='444' width='156' height='156'/%3E%3C/g%3E%3Cg fill='url(%23w)'%3E%3Crect x='-10' y='284' width='88' height='316'/%3E%3Crect x='88' y='396' width='96' height='204'/%3E%3Crect x='194' y='351' width='129' height='249'/%3E%3Crect x='334' y='272' width='77' height='328'/%3E%3Crect x='421' y='239' width='144' height='361'/%3E%3Crect x='575' y='293' width='152' height='307'/%3E%3Crect x='737' y='444' width='156' height='156'/%3E%3C/g%3E%3C/svg%3E" alt="School buildings under a violet sky"><figcaption><strong>Lantern School, Seoul</strong><span>A primary school lit from within</span></figcaption></figure>
<figure><img src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 800 600' preserveAspectRatio='xMidYMid slice'%3E%3Cdefs%3E%3ClinearGradient id='k' x1='0' y1='0' x2='0' y2='1'%3E%3Cstop offset='0' stop-color='%233a1631'/%3E%3Cstop offset='.6' stop-color='%23b04a5a'/%3E%3Cstop offset='1' stop-color='%23f7c59f'/%3E%3C/linearGradient%3E%3Cpattern id='w' width='36' height='44' patternUnits='userSpaceOnUse'%3E%3Crect x='8' y='10' width='8' height='11' fill='%23ffe0a3' opacity='.8'/%3E%3Crect x='22' y='32' width='8' height='11' fill='%23ffe0a3' opacity='.45'/%3E%3C/pattern%3E%3CradialGradient id='h'%3E%3Cstop offset='0' stop-color='%23fff0d6' stop-opacity='.85'/%3E%3Cstop offset='1' stop-color='%23fff0d6' stop-opacity='0'/%3E%3C/radialGradient%3E%3C/defs%3E%3Crect width='800' height='600' fill='url(%23k)'/%3E%3Ccircle cx='420' cy='340' r='190' fill='url(%23h)'/%3E%3Ccircle cx='420' cy='340' r='54' fill='%23fff0d6'/%3E%3Cg fill='%235e2440' opacity='.9'%3E%3Crect x='0' y='282' width='100' height='318'/%3E%3Crect x='104' y='302' width='84' height='298'/%3E%3Crect x='193' y='273' width='75' height='327'/%3E%3Crect x='272' y='323' width='106' height='277'/%3E%3Crect x='382' y='347' width='90' height='253'/%3E%3Crect x='476' y='330' width='81' height='270'/%3E%3Crect x='561' y='323' width='63' height='277'/%3E%3Crect x='628' y='241' width='96' height='359'/%3E%3Crect x='727' y='251' width='48' height='349'/%3E%3Crect x='779' y='321' width='45' height='279'/%3E%3C/g%3E%3Cg fill='%2324101f'%3E%3Crect x='-10' y='432' width='84' height='168'/%3E%3Crect x='84' y='399' width='160' height='201'/%3E%3Crect x='253' y='417' width='127' height='183'/%3E%3Crect x='390' y='314' width='111' height='286'/%3E%3Crect x='512' y='238' width='82' height='362'/%3E%3Crect x='604' y='245' width='150' height='355'/%3E%3Crect x='764' y='241' width='150' height='359'/%3E%3C/g%3E%3Cg fill='url(%23w)'%3E%3Crect x='-10' y='432' width='84' height='168'/%3E%3Crect x='84' y='399' width='160' height='201'/%3E%3Crect x='253' y='417' width='127' height='183'/%3E%3Crect x='390' y='314' width='111' height='286'/%3E%3Crect x='512' y='238' width='82' height='362'/%3E%3Crect x='604' y='245' width='150' height='355'/%3E%3Crect x='764' y='241' width='150' height='359'/%3E%3C/g%3E%3C/svg%3E" alt="Market halls in a pink sunset"><figcaption><strong>Rose Market, Marrakech</strong><span>A covered market for 140 stalls</span></figcaption></figure>
<figure><img src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 800 600' preserveAspectRatio='xMidYMid slice'%3E%3Cdefs%3E%3ClinearGradient id='k' x1='0' y1='0' x2='0' y2='1'%3E%3Cstop offset='0' stop-color='%232b2410'/%3E%3Cstop offset='.6' stop-color='%238c6a2f'/%3E%3Cstop offset='1' stop-color='%23f3d58a'/%3E%3C/linearGradient%3E%3Cpattern id='w' width='36' height='44' patternUnits='userSpaceOnUse'%3E%3Crect x='8' y='10' width='8' height='11' fill='%23ffe6a0' opacity='.8'/%3E%3Crect x='22' y='32' width='8' height='11' fill='%23ffe6a0' opacity='.45'/%3E%3C/pattern%3E%3CradialGradient id='h'%3E%3Cstop offset='0' stop-color='%23fff5d1' stop-opacity='.85'/%3E%3Cstop offset='1' stop-color='%23fff5d1' stop-opacity='0'/%3E%3C/radialGradient%3E%3C/defs%3E%3Crect width='800' height='600' fill='url(%23k)'/%3E%3Ccircle cx='260' cy='280' r='190' fill='url(%23h)'/%3E%3Ccircle cx='260' cy='280' r='54' fill='%23fff5d1'/%3E%3Cg fill='%234a3a17' opacity='.9'%3E%3Crect x='0' y='234' width='48' height='366'/%3E%3Crect x='52' y='273' width='49' height='327'/%3E%3Crect x='105' y='384' width='103' height='216'/%3E%3Crect x='211' y='244' width='102' height='356'/%3E%3Crect x='317' y='228' width='109' height='372'/%3E%3Crect x='431' y='319' width='94' height='281'/%3E%3Crect x='528' y='266' width='57' height='334'/%3E%3Crect x='590' y='322' width='102' height='278'/%3E%3Crect x='695' y='321' width='56' height='279'/%3E%3Crect x='756' y='295' width='102' height='305'/%3E%3C/g%3E%3Cg fill='%231c170a'%3E%3Crect x='-10' y='307' width='102' height='293'/%3E%3Crect x='102' y='373' width='136' height='227'/%3E%3Crect x='248' y='353' width='135' height='247'/%3E%3Crect x='393' y='378' width='88' height='222'/%3E%3Crect x='491' y='221' width='159' height='379'/%3E%3Crect x='660' y='249' width='127' height='351'/%3E%3Crect x='797' y='404' width='153' height='196'/%3E%3C/g%3E%3Cg fill='url(%23w)'%3E%3Crect x='-10' y='307' width='102' height='293'/%3E%3Crect x='102' y='373' width='136' height='227'/%3E%3Crect x='248' y='353' width='135' height='247'/%3E%3Crect x='393' y='378' width='88' height='222'/%3E%3Crect x='491' y='221' width='159' height='379'/%3E%3Crect x='660' y='249' width='127' height='351'/%3E%3Crect x='797' y='404' width='153' height='196'/%3E%3C/g%3E%3C/svg%3E" alt="Hotel blocks in golden desert light"><figcaption><strong>Sand Court, Dubai</strong><span>Courtyard hotel with shaded terraces</span></figcaption></figure>
</mv-mosaic>
</section>
</div>
API
Attributes
Name Type Default Description variantmosaic | rail mosaicmosaic: a grid where the active tile spans 2×2; rail: a strip of expanding panels. activateclick | hover clickmosaic: hover also activates the hovered tile after 140 ms (fine pointers; touch still taps). labelstring Accessible name of the group. durationnumber 640Rearrangement duration (ms), mosaic only.
Properties
Name Type Description activeIndexnumber Index of the active tile (settable). itemsElement[] Tiles (direct children, except [data-mv-ignore]).
Methods
Name Description select(index, { focus })Activates a tile (mosaic: with an animated rearrangement).
Events
Name Description mv-changeActive tile changed. detail: { index, item }.
Content structure
Name Description childrenOne tile per child, typically <figure><img alt><figcaption><strong>Title</strong><span>Detail</span></figcaption></figure>. data-active = tile open initially.
CSS classes
Name Description mv-mosaic-itemAdded to every tile; data-active marks the chosen tile, data-open the widened rail panel.
CSS variables
Name Default Description --mv-mosaic-columns4Mosaic columns (the active tile spans 2). --mv-mosaic-row8.5remRow height. --mv-mosaic-gapvar(--mv-space-2)Gap. --mv-mosaic-radius14pxTile corner radius, kept during the morph. --mv-mosaic-rail-height22remrail: strip height. --mv-mosaic-grow5rail: grow factor of the open panel (neighbours take 14% of the extra). --mv-mosaic-scrim / --mv-mosaic-caption-coloroklch(0.16 0.02 280 / 0.74) / oklch(0.99 0 0)Caption gradient and text color over the photos.
Accessibility
Named role="group"; each tile is a role="button" with aria-pressed (active tile) and a name taken from its caption, else its image alt. Roving tabindex: one tile in the tab order, arrow keys in visual order (the large tile first), Home/End, Enter/Space to activate. Links inside the active tile work normally. In rail, keyboard focus widens a panel like hover, and arrow keys also activate it. The morph only captures the tiles: the rest of the page stays live and clickable. Reduced motion (OS setting or data-motion="reduce") or no View Transitions: the grid rearranges at once. Forced colors: tiles outlined, active tile in Highlight, captions on Canvas.