Product Card <mv-product-card>

Card de produto em três formatos: bloco de grade (segunda imagem ao passar o mouse, badges “New” / “−20%”, coração de lista de desejos, adição rápida por tamanho com confirmação, amostras de cor, estado esgotado), linha de carrinho (quantidade, total da linha recalculado, remoção animada) e linha de resumo compacta; link estendido acessível, container queries.

CategoriaExibição de dados
TipoWeb Component (<mv-product-card>)
Statusestável
Também instalalike-button, number-field, price, quantity, rating
Keywordsproduct, produit, card, carte, e-commerce, quick-add, wishlist, cart-line, hover-image, badge

When to use

  • A shop grid shows product tiles with a hover image, badges, wishlist and quick add by size
  • A cart or drawer lists products with quantity controls, recalculated line totals and removal
  • An order summary needs compact product lines with a thumbnail and quantity badge

Avoid when

  • The need is a full cart with promo codes, shipping and totals → use Cart instead
  • The card is not a product but an article, project or generic content → use Card instead
  • A product detail page needs variant selection, stock and add to cart → use Buy Box instead

Instalação

node scripts/add.mjs product-card --out ./src/marvelous

Agente de IA com o servidor MCP do Marvelous UI: install_components({ slugs: ["product-card"], target_dir: "<absolute path>/src/marvelous", framework: "react" }).

Arquivos copiados (dependências incluídas): tokens/tokens.css, core/base.css, core/dismiss.js, core/dom.js, core/element.js, core/motion.js, components/product-card/product-card.js, components/product-card/product-card.css, components/like-button/like-button.js, components/like-button/like-button.css, components/number-field/number-field.js, components/number-field/number-field.css, components/price/price.js, components/price/price.css, components/quantity/quantity.js, components/quantity/quantity.css, core/form.js, components/rating/rating.js, components/rating/rating.css.

Uso

Marcação de referência, para usar como ponto de partida e personalizar com atributos, data-* e variáveis CSS:

<div id="pc-demo" style="display:grid;gap:2.5rem;width:min(100%,64rem);margin-inline:auto">
  <section style="display:grid;grid-template-columns:repeat(auto-fill,minmax(min(100%,max(9rem,22%)),1fr));gap:2rem clamp(.75rem,2vw,1.25rem)" aria-label="New arrivals">
    <mv-product-card data-id="pull-merinos" data-title="Merino Crewneck Sweater" data-price="89" data-compare-at="112">
      <article class="mv-product-card">
        <div class="mv-product-card-media">
          <img class="mv-product-card-image" src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 400 500'%3E%3Cdefs%3E%3ClinearGradient id='bg' x1='0' y1='0' x2='0' y2='1'%3E%3Cstop offset='0' stop-color='oklch(0.97 0.012 80)'/%3E%3Cstop offset='1' stop-color='oklch(0.91 0.025 75)'/%3E%3C/linearGradient%3E%3CradialGradient id='fl'%3E%3Cstop offset='0' stop-color='black' stop-opacity='.22'/%3E%3Cstop offset='1' stop-color='black' stop-opacity='0'/%3E%3C/radialGradient%3E%3ClinearGradient id='sh' x1='0' x2='1'%3E%3Cstop offset='0' stop-color='white' stop-opacity='.22'/%3E%3Cstop offset='.55' stop-color='white' stop-opacity='0'/%3E%3Cstop offset='1' stop-color='black' stop-opacity='.16'/%3E%3C/linearGradient%3E%3C/defs%3E%3Crect width='400' height='500' fill='url(%23bg)'/%3E%3Cdefs%3E%3Cpattern id='k' width='12' height='10' patternUnits='userSpaceOnUse'%3E%3Cpath d='M0 0l6 8 6-8' fill='none' stroke='black' stroke-opacity='.09' stroke-width='1.6'/%3E%3C/pattern%3E%3C/defs%3E%3Cellipse cx='200' cy='420' rx='150' ry='18' fill='url(%23fl)' opacity='1'/%3E%3Cpath d='M160 118 Q200 142 240 118 L276 128 Q300 140 310 176 L336 318 L300 331 L268 222 L267 388 Q200 397 133 388 L132 222 L100 331 L64 318 L90 176 Q100 140 124 128 Z' fill='oklch(0.8 0.05 75)'/%3E%3Cpath d='M160 118 Q200 142 240 118 L276 128 Q300 140 310 176 L336 318 L300 331 L268 222 L267 388 Q200 397 133 388 L132 222 L100 331 L64 318 L90 176 Q100 140 124 128 Z' fill='url(%23k)'/%3E%3Cpath d='M160 118 Q200 142 240 118 L276 128 Q300 140 310 176 L336 318 L300 331 L268 222 L267 388 Q200 397 133 388 L132 222 L100 331 L64 318 L90 176 Q100 140 124 128 Z' fill='url(%23sh)'/%3E%3Cpath d='M160 118 Q200 152 240 118 Q200 136 160 118Z' fill='black' fill-opacity='.22'/%3E%3Cpath d='M154 116 Q200 160 246 116' fill='none' stroke='black' stroke-opacity='.12' stroke-width='5'/%3E%3Cpath d='M133 370 Q200 379 267 370 L267 388 Q200 397 133 388 Z' fill='black' fill-opacity='.1'/%3E%3Cpath d='M64 318 L100 331 L103 316 L68 303 Z' fill='black' fill-opacity='.1'/%3E%3Cpath d='M336 318 L300 331 L297 316 L332 303 Z' fill='black' fill-opacity='.1'/%3E%3Cpath d='M132 222 L133 380 M268 222 L267 380' stroke='black' stroke-opacity='.08' stroke-width='3'/%3E%3C/svg%3E" alt="Merino Crewneck Sweater in Sand">
          <img class="mv-product-card-image" data-alt src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 400 500'%3E%3Cdefs%3E%3ClinearGradient id='bg' x1='0' y1='0' x2='0' y2='1'%3E%3Cstop offset='0' stop-color='oklch(0.97 0.012 80)'/%3E%3Cstop offset='1' stop-color='oklch(0.91 0.025 75)'/%3E%3C/linearGradient%3E%3CradialGradient id='fl'%3E%3Cstop offset='0' stop-color='black' stop-opacity='.22'/%3E%3Cstop offset='1' stop-color='black' stop-opacity='0'/%3E%3C/radialGradient%3E%3ClinearGradient id='sh' x1='0' x2='1'%3E%3Cstop offset='0' stop-color='white' stop-opacity='.22'/%3E%3Cstop offset='.55' stop-color='white' stop-opacity='0'/%3E%3Cstop offset='1' stop-color='black' stop-opacity='.16'/%3E%3C/linearGradient%3E%3C/defs%3E%3Crect width='400' height='500' fill='url(%23bg)'/%3E%3Cdefs%3E%3Cpattern id='k' width='12' height='10' patternUnits='userSpaceOnUse'%3E%3Cpath d='M0 0l6 8 6-8' fill='none' stroke='black' stroke-opacity='.09' stroke-width='1.6'/%3E%3C/pattern%3E%3C/defs%3E%3Crect x='0' y='0' width='400' height='500' fill='white' fill-opacity='.18'/%3E%3Cpath d='M200 58 q0-16 12-16 q12 0 12 12 q0 10-12 14 L200 78' fill='none' stroke='oklch(0.55 0.02 60)' stroke-width='5' stroke-linecap='round'/%3E%3Cpath d='M200 78 L96 124 L304 124 Z' fill='none' stroke='oklch(0.6 0.08 60)' stroke-width='8' stroke-linejoin='round'/%3E%3Cg transform='translate(40 30) scale(.8)'%3E%3Cpath d='M160 118 Q200 142 240 118 L276 128 Q300 140 310 176 L336 318 L300 331 L268 222 L267 388 Q200 397 133 388 L132 222 L100 331 L64 318 L90 176 Q100 140 124 128 Z' fill='oklch(0.8 0.05 75)'/%3E%3Cpath d='M160 118 Q200 142 240 118 L276 128 Q300 140 310 176 L336 318 L300 331 L268 222 L267 388 Q200 397 133 388 L132 222 L100 331 L64 318 L90 176 Q100 140 124 128 Z' fill='url(%23k)'/%3E%3Cpath d='M160 118 Q200 142 240 118 L276 128 Q300 140 310 176 L336 318 L300 331 L268 222 L267 388 Q200 397 133 388 L132 222 L100 331 L64 318 L90 176 Q100 140 124 128 Z' fill='url(%23sh)'/%3E%3Cpath d='M160 118 Q200 152 240 118 Q200 136 160 118Z' fill='black' fill-opacity='.2'/%3E%3Cpath d='M133 372 Q200 380 267 372 L267 388 Q200 397 133 388 Z' fill='black' fill-opacity='.1'/%3E%3C/g%3E%3Cpath d='M300 470 c-4-60 6-110 30-150 c-2 50-10 100-12 150z' fill='oklch(0.55 0.08 150)' opacity='.55'/%3E%3Cpath d='M318 470 c8-52 30-86 58-104 c-14 38-30 72-40 104z' fill='oklch(0.5 0.08 150)' opacity='.5'/%3E%3Crect x='292' y='452' width='64' height='48' rx='6' fill='oklch(0.72 0.06 55)' opacity='.9'/%3E%3C/svg%3E" alt="">
          <div class="mv-product-card-badges"><span class="mv-product-card-badge">New</span><span class="mv-product-card-badge" data-tone="sale">−20%</span></div>
          <mv-like class="mv-product-card-wishlist" label="Add to wishlist: Merino Crewneck Sweater"></mv-like>
          <div class="mv-product-card-quick" role="group" aria-label="Quick add, choose a size">
            <p class="mv-product-card-quick-title">Quick add</p>
            <div class="mv-product-card-sizes">
              <button type="button" data-add="XS" disabled aria-label="XS, sold out">XS</button>
              <button type="button" data-add="S">S</button>
              <button type="button" data-add="M">M</button>
              <button type="button" data-add="L">L</button>
              <button type="button" data-add="XL">XL</button>
            </div>
          </div>
        </div>
        <div class="mv-product-card-body">
          <p class="mv-product-card-vendor">Lumen Supply Co.</p>
          <h3 class="mv-product-card-title"><a class="mv-product-card-link" href="#pull">Merino Crewneck Sweater</a></h3>
          <mv-rating readonly value="4.6" count="128" data-variant="compact" data-size="sm"></mv-rating>
          <mv-price value="89" compare-at="112" discount="none" data-size="sm"></mv-price>
          <div class="mv-product-card-colors"><span style="--c:oklch(0.8 0.05 75)"></span><span style="--c:oklch(0.34 0.05 262)"></span><span style="--c:oklch(0.7 0.06 150)"></span><span class="mv-product-card-more">+2 colors</span></div>
        </div>
      </article>
    </mv-product-card>

    <mv-product-card data-id="basket-aurore" data-title="Aurora Sneaker in Recycled Leather" data-price="139">
      <article class="mv-product-card">
        <div class="mv-product-card-media">
          <img class="mv-product-card-image" src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 400 500'%3E%3Cdefs%3E%3ClinearGradient id='bg' x1='0' y1='0' x2='0' y2='1'%3E%3Cstop offset='0' stop-color='oklch(0.96 0.015 230)'/%3E%3Cstop offset='1' stop-color='oklch(0.88 0.035 235)'/%3E%3C/linearGradient%3E%3CradialGradient id='fl'%3E%3Cstop offset='0' stop-color='black' stop-opacity='.22'/%3E%3Cstop offset='1' stop-color='black' stop-opacity='0'/%3E%3C/radialGradient%3E%3ClinearGradient id='sh' x1='0' x2='1'%3E%3Cstop offset='0' stop-color='white' stop-opacity='.22'/%3E%3Cstop offset='.55' stop-color='white' stop-opacity='0'/%3E%3Cstop offset='1' stop-color='black' stop-opacity='.16'/%3E%3C/linearGradient%3E%3C/defs%3E%3Crect width='400' height='500' fill='url(%23bg)'/%3E%3Cellipse cx='200' cy='322' rx='170' ry='14' fill='url(%23fl)' opacity='1'/%3E%3Cg transform='translate(-10 10)'%3E%3Cpath d='M62 300 L358 300 C362 320 350 336 328 336 L86 336 C68 336 58 320 62 300 Z' fill='oklch(0.97 0.005 90)'/%3E%3Cpath d='M62 318 L360 318' stroke='black' stroke-opacity='.08' stroke-width='3'/%3E%3Cpath d='M68 300 C66 252 106 236 150 232 L206 198 C226 186 252 188 264 204 L292 240 C324 250 348 262 352 286 L354 300 Z' fill='oklch(0.78 0.07 235)'/%3E%3Cpath d='M68 300 C66 252 106 236 150 232 L206 198 C226 186 252 188 264 204 L292 240 C324 250 348 262 352 286 L354 300 Z' fill='url(%23sh)'/%3E%3Cpath d='M292 240 C324 250 348 262 352 286 L354 300 L318 300 C318 278 306 256 292 240Z' fill='black' fill-opacity='.08'/%3E%3Cpath d='M140 292 C184 258 236 250 306 264' fill='none' stroke='white' stroke-opacity='.85' stroke-width='9' stroke-linecap='round'/%3E%3Cpath d='M214 206 l26 36 M226 200 l26 36 M200 214 l28 34' stroke='oklch(0.97 0.005 90)' stroke-width='5' stroke-linecap='round'/%3E%3Cpath d='M206 198 C226 186 252 188 264 204' fill='none' stroke='black' stroke-opacity='.18' stroke-width='5'/%3E%3Ccircle cx='96' cy='262' r='5' fill='white' fill-opacity='.8'/%3E%3C/g%3E%3C/svg%3E" alt="Aurora Sneaker in Sky Blue">
          <img class="mv-product-card-image" data-alt src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 400 500'%3E%3Cdefs%3E%3ClinearGradient id='bg' x1='0' y1='0' x2='0' y2='1'%3E%3Cstop offset='0' stop-color='oklch(0.96 0.015 230)'/%3E%3Cstop offset='1' stop-color='oklch(0.88 0.035 235)'/%3E%3C/linearGradient%3E%3CradialGradient id='fl'%3E%3Cstop offset='0' stop-color='black' stop-opacity='.22'/%3E%3Cstop offset='1' stop-color='black' stop-opacity='0'/%3E%3C/radialGradient%3E%3ClinearGradient id='sh' x1='0' x2='1'%3E%3Cstop offset='0' stop-color='white' stop-opacity='.22'/%3E%3Cstop offset='.55' stop-color='white' stop-opacity='0'/%3E%3Cstop offset='1' stop-color='black' stop-opacity='.16'/%3E%3C/linearGradient%3E%3C/defs%3E%3Crect width='400' height='500' fill='url(%23bg)'/%3E%3Cellipse cx='210' cy='372' rx='170' ry='16' fill='url(%23fl)' opacity='1'/%3E%3Cg transform='translate(40 70) scale(.85)'%3E%3Cpath d='M62 300 L358 300 C362 320 350 336 328 336 L86 336 C68 336 58 320 62 300 Z' fill='oklch(0.97 0.005 90)'/%3E%3Cpath d='M62 318 L360 318' stroke='black' stroke-opacity='.08' stroke-width='3'/%3E%3Cpath d='M68 300 C66 252 106 236 150 232 L206 198 C226 186 252 188 264 204 L292 240 C324 250 348 262 352 286 L354 300 Z' fill='oklch(0.78 0.07 235)'/%3E%3Cpath d='M68 300 C66 252 106 236 150 232 L206 198 C226 186 252 188 264 204 L292 240 C324 250 348 262 352 286 L354 300 Z' fill='url(%23sh)'/%3E%3Cpath d='M292 240 C324 250 348 262 352 286 L354 300 L318 300 C318 278 306 256 292 240Z' fill='black' fill-opacity='.08'/%3E%3Cpath d='M140 292 C184 258 236 250 306 264' fill='none' stroke='white' stroke-opacity='.85' stroke-width='9' stroke-linecap='round'/%3E%3Cpath d='M214 206 l26 36 M226 200 l26 36 M200 214 l28 34' stroke='oklch(0.97 0.005 90)' stroke-width='5' stroke-linecap='round'/%3E%3Cpath d='M206 198 C226 186 252 188 264 204' fill='none' stroke='black' stroke-opacity='.18' stroke-width='5'/%3E%3Ccircle cx='96' cy='262' r='5' fill='white' fill-opacity='.8'/%3E%3C/g%3E%3Cg transform='translate(-10 30) scale(.85)' opacity='1'%3E%3Cpath d='M62 300 L358 300 C362 320 350 336 328 336 L86 336 C68 336 58 320 62 300 Z' fill='oklch(0.97 0.005 90)'/%3E%3Cpath d='M62 318 L360 318' stroke='black' stroke-opacity='.08' stroke-width='3'/%3E%3Cpath d='M68 300 C66 252 106 236 150 232 L206 198 C226 186 252 188 264 204 L292 240 C324 250 348 262 352 286 L354 300 Z' fill='oklch(0.78 0.07 235)'/%3E%3Cpath d='M68 300 C66 252 106 236 150 232 L206 198 C226 186 252 188 264 204 L292 240 C324 250 348 262 352 286 L354 300 Z' fill='url(%23sh)'/%3E%3Cpath d='M292 240 C324 250 348 262 352 286 L354 300 L318 300 C318 278 306 256 292 240Z' fill='black' fill-opacity='.08'/%3E%3Cpath d='M140 292 C184 258 236 250 306 264' fill='none' stroke='white' stroke-opacity='.85' stroke-width='9' stroke-linecap='round'/%3E%3Cpath d='M214 206 l26 36 M226 200 l26 36 M200 214 l28 34' stroke='oklch(0.97 0.005 90)' stroke-width='5' stroke-linecap='round'/%3E%3Cpath d='M206 198 C226 186 252 188 264 204' fill='none' stroke='black' stroke-opacity='.18' stroke-width='5'/%3E%3Ccircle cx='96' cy='262' r='5' fill='white' fill-opacity='.8'/%3E%3C/g%3E%3C/svg%3E" alt="">
          <div class="mv-product-card-badges"><span class="mv-product-card-badge" data-tone="dark">Eco-designed</span></div>
          <mv-like class="mv-product-card-wishlist" label="Add to wishlist: Aurora Sneaker" pressed></mv-like>
          <div class="mv-product-card-quick" role="group" aria-label="Quick add, choose a size">
            <p class="mv-product-card-quick-title">Choose a size</p>
            <div class="mv-product-card-sizes">
              <button type="button" data-add="7">7</button>
              <button type="button" data-add="8">8</button>
              <button type="button" data-add="9" disabled aria-label="9, sold out">9</button>
              <button type="button" data-add="10">10</button>
              <button type="button" data-add="11">11</button>
            </div>
          </div>
        </div>
        <div class="mv-product-card-body">
          <p class="mv-product-card-vendor">Aurora Footwear</p>
          <h3 class="mv-product-card-title"><a class="mv-product-card-link" href="#basket">Aurora Sneaker in Recycled Leather</a></h3>
          <mv-rating readonly value="4.8" count="2413" data-variant="compact" data-size="sm"></mv-rating>
          <mv-price value="139" data-size="sm"></mv-price>
          <div class="mv-product-card-colors"><span style="--c:oklch(0.78 0.07 235)"></span><span style="--c:oklch(0.58 0.13 38)"></span><span style="--c:oklch(0.97 0.005 90)"></span></div>
        </div>
      </article>
    </mv-product-card>

    <mv-product-card data-id="lampe-opaline" data-title="Opaline Table Lamp" data-price="129">
      <article class="mv-product-card">
        <div class="mv-product-card-media">
          <img class="mv-product-card-image" src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 400 500'%3E%3Cdefs%3E%3ClinearGradient id='bg' x1='0' y1='0' x2='0' y2='1'%3E%3Cstop offset='0' stop-color='oklch(0.97 0.02 85)'/%3E%3Cstop offset='1' stop-color='oklch(0.9 0.04 80)'/%3E%3C/linearGradient%3E%3CradialGradient id='fl'%3E%3Cstop offset='0' stop-color='black' stop-opacity='.22'/%3E%3Cstop offset='1' stop-color='black' stop-opacity='0'/%3E%3C/radialGradient%3E%3ClinearGradient id='sh' x1='0' x2='1'%3E%3Cstop offset='0' stop-color='white' stop-opacity='.22'/%3E%3Cstop offset='.55' stop-color='white' stop-opacity='0'/%3E%3Cstop offset='1' stop-color='black' stop-opacity='.16'/%3E%3C/linearGradient%3E%3C/defs%3E%3Crect width='400' height='500' fill='url(%23bg)'/%3E%3Cdefs%3E%3CradialGradient id='gb' cx='.38' cy='.34'%3E%3Cstop offset='0' stop-color='white'/%3E%3Cstop offset='1' stop-color='oklch(0.97 0.01 90)' stop-opacity='.85'/%3E%3C/radialGradient%3E%3C/defs%3E%3Cellipse cx='200' cy='424' rx='110' ry='12' fill='url(%23fl)' opacity='1'/%3E%3Ccircle cx='200' cy='210' r='118' fill='url(%23gb)'/%3E%3Ccircle cx='200' cy='210' r='118' fill='none' stroke='black' stroke-opacity='.06' stroke-width='2'/%3E%3Cpath d='M168 318 L232 318 L246 404 Q200 420 154 404 Z' fill='oklch(0.74 0.13 75)'/%3E%3Cpath d='M168 318 L232 318 L246 404 Q200 420 154 404 Z' fill='url(%23sh)'/%3E%3Crect x='160' y='312' width='80' height='12' rx='6' fill='oklch(0.72 0.1 80)'/%3E%3C/svg%3E" alt="Opaline lamp, glass globe on a brass base">
          <img class="mv-product-card-image" data-alt src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 400 500'%3E%3Cdefs%3E%3ClinearGradient id='bg' x1='0' y1='0' x2='0' y2='1'%3E%3Cstop offset='0' stop-color='oklch(0.3 0.02 270)'/%3E%3Cstop offset='1' stop-color='oklch(0.18 0.015 270)'/%3E%3C/linearGradient%3E%3CradialGradient id='fl'%3E%3Cstop offset='0' stop-color='black' stop-opacity='.22'/%3E%3Cstop offset='1' stop-color='black' stop-opacity='0'/%3E%3C/radialGradient%3E%3ClinearGradient id='sh' x1='0' x2='1'%3E%3Cstop offset='0' stop-color='white' stop-opacity='.22'/%3E%3Cstop offset='.55' stop-color='white' stop-opacity='0'/%3E%3Cstop offset='1' stop-color='black' stop-opacity='.16'/%3E%3C/linearGradient%3E%3C/defs%3E%3Crect width='400' height='500' fill='url(%23bg)'/%3E%3Cdefs%3E%3CradialGradient id='gl'%3E%3Cstop offset='0' stop-color='oklch(0.95 0.08 85)' stop-opacity='.9'/%3E%3Cstop offset='.45' stop-color='oklch(0.85 0.1 75)' stop-opacity='.35'/%3E%3Cstop offset='1' stop-color='oklch(0.8 0.1 70)' stop-opacity='0'/%3E%3C/radialGradient%3E%3CradialGradient id='gb' cx='.38' cy='.34'%3E%3Cstop offset='0' stop-color='white'/%3E%3Cstop offset='1' stop-color='oklch(0.97 0.05 90)' stop-opacity='.85'/%3E%3C/radialGradient%3E%3C/defs%3E%3Ccircle cx='200' cy='200' r='220' fill='url(%23gl)'/%3E%3Cellipse cx='200' cy='424' rx='110' ry='12' fill='url(%23fl)' opacity='1'/%3E%3Ccircle cx='200' cy='210' r='118' fill='url(%23gb)'/%3E%3Cpath d='M168 318 L232 318 L246 404 Q200 420 154 404 Z' fill='oklch(0.74 0.13 75)'/%3E%3Cpath d='M168 318 L232 318 L246 404 Q200 420 154 404 Z' fill='url(%23sh)'/%3E%3Crect x='160' y='312' width='80' height='12' rx='6' fill='oklch(0.72 0.1 80)'/%3E%3C/svg%3E" alt="">
          <mv-like class="mv-product-card-wishlist" label="Add to wishlist: Opaline Lamp"></mv-like>
          <div class="mv-product-card-quick">
            <button type="button" class="mv-product-card-quick-add" data-add>
              <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 7h12l1 13H5L6 7Z"/><path d="M9 7a3 3 0 0 1 6 0"/></svg>
              Add to cart
            </button>
          </div>
        </div>
        <div class="mv-product-card-body">
          <p class="mv-product-card-vendor">Glassworks Studio</p>
          <h3 class="mv-product-card-title"><a class="mv-product-card-link" href="#lampe">Opaline Table Lamp</a></h3>
          <mv-rating readonly value="4.4" count="56" data-variant="compact" data-size="sm"></mv-rating>
          <mv-price value="129" compare-at="159" data-size="sm"></mv-price>
        </div>
      </article>
    </mv-product-card>

    <mv-product-card data-id="casque-onde" data-title="Wave Wireless Headphones" data-price="189.9">
      <article class="mv-product-card" data-state="sold-out">
        <div class="mv-product-card-media">
          <img class="mv-product-card-image" src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 400 500'%3E%3Cdefs%3E%3ClinearGradient id='bg' x1='0' y1='0' x2='0' y2='1'%3E%3Cstop offset='0' stop-color='oklch(0.97 0.012 20)'/%3E%3Cstop offset='1' stop-color='oklch(0.9 0.03 15)'/%3E%3C/linearGradient%3E%3CradialGradient id='fl'%3E%3Cstop offset='0' stop-color='black' stop-opacity='.22'/%3E%3Cstop offset='1' stop-color='black' stop-opacity='0'/%3E%3C/radialGradient%3E%3ClinearGradient id='sh' x1='0' x2='1'%3E%3Cstop offset='0' stop-color='white' stop-opacity='.22'/%3E%3Cstop offset='.55' stop-color='white' stop-opacity='0'/%3E%3Cstop offset='1' stop-color='black' stop-opacity='.16'/%3E%3C/linearGradient%3E%3C/defs%3E%3Crect width='400' height='500' fill='url(%23bg)'/%3E%3Cellipse cx='200' cy='392' rx='140' ry='14' fill='url(%23fl)' opacity='1'/%3E%3Cpath d='M112 270 C112 150 288 150 288 270' fill='none' stroke='oklch(0.8 0.07 15)' stroke-width='22' stroke-linecap='round'/%3E%3Cpath d='M112 270 C112 150 288 150 288 270' fill='none' stroke='white' stroke-opacity='.2' stroke-width='6' stroke-linecap='round' transform='translate(0 -6)'/%3E%3Crect x='80' y='250' width='70' height='112' rx='34' fill='oklch(0.8 0.07 15)'/%3E%3Crect x='250' y='250' width='70' height='112' rx='34' fill='oklch(0.8 0.07 15)'/%3E%3Crect x='80' y='250' width='70' height='112' rx='34' fill='url(%23sh)'/%3E%3Crect x='250' y='250' width='70' height='112' rx='34' fill='url(%23sh)'/%3E%3Crect x='134' y='262' width='22' height='88' rx='11' fill='oklch(0.3 0.01 270)'/%3E%3Crect x='244' y='262' width='22' height='88' rx='11' fill='oklch(0.3 0.01 270)'/%3E%3Ccircle cx='115' cy='306' r='9' fill='white' fill-opacity='.35'/%3E%3C/svg%3E" alt="Wave Wireless Headphones in Blush Pink">
          <div class="mv-product-card-badges"><span class="mv-product-card-badge">Sold out</span></div>
          <mv-like class="mv-product-card-wishlist" label="Add to wishlist: Wave Wireless Headphones"></mv-like>
        </div>
        <div class="mv-product-card-body">
          <p class="mv-product-card-vendor">Wave Audio</p>
          <h3 class="mv-product-card-title"><a class="mv-product-card-link" href="#casque">Wave Wireless Headphones with Active Noise Cancelling</a></h3>
          <mv-rating readonly value="4.2" count="311" data-variant="compact" data-size="sm"></mv-rating>
          <mv-price value="189.9" data-size="sm"></mv-price>
          <p class="mv-product-card-subtitle">Back in stock Oct 14</p>
        </div>
      </article>
    </mv-product-card>
  </section>

  <section style="display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,22rem),1fr));gap:1.5rem 2.5rem;align-items:start">
    <div id="pc-demo-lines" style="display:grid;gap:1.25rem;padding:1.25rem;border:1px solid var(--mv-border);border-radius:var(--mv-radius-xl);background:var(--mv-surface)">
      <h3 style="margin:0;font-size:.9375rem">Cart line</h3>
      <mv-product-card data-id="pull-merinos-m" data-title="Merino Crewneck Sweater" data-price="89" data-compare-at="112">
        <article class="mv-product-card" data-variant="horizontal">
          <a class="mv-product-card-media" href="#pull" tabindex="-1" aria-hidden="true"><img class="mv-product-card-image" src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 400 500'%3E%3Cdefs%3E%3ClinearGradient id='bg' x1='0' y1='0' x2='0' y2='1'%3E%3Cstop offset='0' stop-color='oklch(0.95 0.012 250)'/%3E%3Cstop offset='1' stop-color='oklch(0.87 0.025 255)'/%3E%3C/linearGradient%3E%3CradialGradient id='fl'%3E%3Cstop offset='0' stop-color='black' stop-opacity='.22'/%3E%3Cstop offset='1' stop-color='black' stop-opacity='0'/%3E%3C/radialGradient%3E%3ClinearGradient id='sh' x1='0' x2='1'%3E%3Cstop offset='0' stop-color='white' stop-opacity='.22'/%3E%3Cstop offset='.55' stop-color='white' stop-opacity='0'/%3E%3Cstop offset='1' stop-color='black' stop-opacity='.16'/%3E%3C/linearGradient%3E%3C/defs%3E%3Crect width='400' height='500' fill='url(%23bg)'/%3E%3Cdefs%3E%3Cpattern id='k' width='12' height='10' patternUnits='userSpaceOnUse'%3E%3Cpath d='M0 0l6 8 6-8' fill='none' stroke='black' stroke-opacity='.09' stroke-width='1.6'/%3E%3C/pattern%3E%3C/defs%3E%3Cellipse cx='200' cy='420' rx='150' ry='18' fill='url(%23fl)' opacity='1'/%3E%3Cpath d='M160 118 Q200 142 240 118 L276 128 Q300 140 310 176 L336 318 L300 331 L268 222 L267 388 Q200 397 133 388 L132 222 L100 331 L64 318 L90 176 Q100 140 124 128 Z' fill='oklch(0.34 0.05 262)'/%3E%3Cpath d='M160 118 Q200 142 240 118 L276 128 Q300 140 310 176 L336 318 L300 331 L268 222 L267 388 Q200 397 133 388 L132 222 L100 331 L64 318 L90 176 Q100 140 124 128 Z' fill='url(%23k)'/%3E%3Cpath d='M160 118 Q200 142 240 118 L276 128 Q300 140 310 176 L336 318 L300 331 L268 222 L267 388 Q200 397 133 388 L132 222 L100 331 L64 318 L90 176 Q100 140 124 128 Z' fill='url(%23sh)'/%3E%3Cpath d='M160 118 Q200 152 240 118 Q200 136 160 118Z' fill='black' fill-opacity='.22'/%3E%3Cpath d='M154 116 Q200 160 246 116' fill='none' stroke='black' stroke-opacity='.12' stroke-width='5'/%3E%3Cpath d='M133 370 Q200 379 267 370 L267 388 Q200 397 133 388 Z' fill='black' fill-opacity='.1'/%3E%3Cpath d='M64 318 L100 331 L103 316 L68 303 Z' fill='black' fill-opacity='.1'/%3E%3Cpath d='M336 318 L300 331 L297 316 L332 303 Z' fill='black' fill-opacity='.1'/%3E%3Cpath d='M132 222 L133 380 M268 222 L267 380' stroke='black' stroke-opacity='.08' stroke-width='3'/%3E%3C/svg%3E" alt=""></a>
          <div class="mv-product-card-body">
            <div class="mv-product-card-head">
              <h4 class="mv-product-card-title"><a href="#pull" style="color:inherit;text-decoration:none">Merino Crewneck Sweater</a></h4>
              <mv-price data-role="total" value="89" compare-at="112" discount="none" data-size="sm"></mv-price>
            </div>
            <p class="mv-product-card-meta">Midnight Blue · Size M</p>
            <p class="mv-product-card-meta" data-role="unit" hidden>$89.00 each</p>
            <div class="mv-product-card-actions">
              <mv-quantity value="1" stock="3" data-size="sm" caption="none" aria-label="Quantity, Merino Crewneck Sweater"></mv-quantity>
              <button type="button" class="mv-product-card-remove" data-remove><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 7h16M10 11v6M14 11v6M6 7l1 13h10l1-13M9 7V4h6v3"/></svg><span class="mv-product-card-remove-text">Remove</span><span class="mv-sr-only"> Merino Crewneck Sweater</span></button>
            </div>
          </div>
        </article>
      </mv-product-card>
      <hr style="margin:0;border:0;border-top:1px solid var(--mv-border)">
      <mv-product-card data-id="mug-sauge" data-title="Glazed Stoneware Mug" data-price="24.9">
        <article class="mv-product-card" data-variant="horizontal">
          <a class="mv-product-card-media" href="#mug" tabindex="-1" aria-hidden="true"><img class="mv-product-card-image" src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 400 500'%3E%3Cdefs%3E%3ClinearGradient id='bg' x1='0' y1='0' x2='0' y2='1'%3E%3Cstop offset='0' stop-color='oklch(0.96 0.015 145)'/%3E%3Cstop offset='1' stop-color='oklch(0.89 0.03 150)'/%3E%3C/linearGradient%3E%3CradialGradient id='fl'%3E%3Cstop offset='0' stop-color='black' stop-opacity='.22'/%3E%3Cstop offset='1' stop-color='black' stop-opacity='0'/%3E%3C/radialGradient%3E%3ClinearGradient id='sh' x1='0' x2='1'%3E%3Cstop offset='0' stop-color='white' stop-opacity='.22'/%3E%3Cstop offset='.55' stop-color='white' stop-opacity='0'/%3E%3Cstop offset='1' stop-color='black' stop-opacity='.16'/%3E%3C/linearGradient%3E%3C/defs%3E%3Crect width='400' height='500' fill='url(%23bg)'/%3E%3Cellipse cx='200' cy='392' rx='130' ry='16' fill='url(%23fl)' opacity='1'/%3E%3Cpath d='M290 220 q64 0 64 60 q0 60-64 60' fill='none' stroke='oklch(0.7 0.06 150)' stroke-width='22' stroke-linecap='round'/%3E%3Cpath d='M110 170 L290 170 L284 370 Q200 392 116 370 Z' fill='oklch(0.86 0.03 75)'/%3E%3Cpath d='M110 170 L290 170 L287 270 C250 286 236 256 206 280 C176 300 150 266 113 284 Z' fill='oklch(0.7 0.06 150)'/%3E%3Cpath d='M110 170 L290 170 L284 370 Q200 392 116 370 Z' fill='url(%23sh)'/%3E%3Cellipse cx='200' cy='170' rx='90' ry='16' fill='oklch(0.36 0.05 55)'/%3E%3Cellipse cx='200' cy='170' rx='90' ry='16' fill='none' stroke='oklch(0.7 0.06 150)' stroke-width='6' style='filter:brightness(1.1)'/%3E%3C/svg%3E" alt=""></a>
          <div class="mv-product-card-body">
            <div class="mv-product-card-head">
              <h4 class="mv-product-card-title"><a href="#mug" style="color:inherit;text-decoration:none">Glazed Stoneware Mug</a></h4>
              <mv-price data-role="total" value="49.8" data-size="sm"></mv-price>
            </div>
            <p class="mv-product-card-meta">Sage · 12 oz</p>
            <p class="mv-product-card-meta" data-role="unit">$24.90 each</p>
            <div class="mv-product-card-actions">
              <mv-quantity value="2" max="10" data-size="sm" caption="none" aria-label="Quantity, Glazed Stoneware Mug"></mv-quantity>
              <button type="button" class="mv-product-card-remove" data-remove><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 7h16M10 11v6M14 11v6M6 7l1 13h10l1-13M9 7V4h6v3"/></svg><span class="mv-product-card-remove-text">Remove</span><span class="mv-sr-only"> Glazed Stoneware Mug</span></button>
            </div>
          </div>
        </article>
      </mv-product-card>
    </div>

    <div style="display:grid;gap:1rem;padding:1.25rem;border:1px solid var(--mv-border);border-radius:var(--mv-radius-xl);background:var(--mv-bg-subtle)">
      <h3 style="margin:0;font-size:.9375rem">Order summary (compact)</h3>
      <mv-product-card data-title="Fig Leaf Scented Candle" data-price="36">
        <article class="mv-product-card" data-variant="compact">
          <div class="mv-product-card-media"><img class="mv-product-card-image" src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 400 500'%3E%3Cdefs%3E%3ClinearGradient id='bg' x1='0' y1='0' x2='0' y2='1'%3E%3Cstop offset='0' stop-color='oklch(0.97 0.012 20)'/%3E%3Cstop offset='1' stop-color='oklch(0.9 0.03 15)'/%3E%3C/linearGradient%3E%3CradialGradient id='fl'%3E%3Cstop offset='0' stop-color='black' stop-opacity='.22'/%3E%3Cstop offset='1' stop-color='black' stop-opacity='0'/%3E%3C/radialGradient%3E%3ClinearGradient id='sh' x1='0' x2='1'%3E%3Cstop offset='0' stop-color='white' stop-opacity='.22'/%3E%3Cstop offset='.55' stop-color='white' stop-opacity='0'/%3E%3Cstop offset='1' stop-color='black' stop-opacity='.16'/%3E%3C/linearGradient%3E%3C/defs%3E%3Crect width='400' height='500' fill='url(%23bg)'/%3E%3Cdefs%3E%3ClinearGradient id='gls' x1='0' x2='1'%3E%3Cstop offset='0' stop-color='white' stop-opacity='.55'/%3E%3Cstop offset='.3' stop-color='white' stop-opacity='.1'/%3E%3Cstop offset='1' stop-color='white' stop-opacity='.35'/%3E%3C/linearGradient%3E%3CradialGradient id='fg'%3E%3Cstop offset='0' stop-color='oklch(0.95 0.12 90)' stop-opacity='.8'/%3E%3Cstop offset='1' stop-color='oklch(0.9 0.12 80)' stop-opacity='0'/%3E%3C/radialGradient%3E%3C/defs%3E%3Cellipse cx='200' cy='404' rx='120' ry='14' fill='url(%23fl)' opacity='1'/%3E%3Crect x='120' y='200' width='160' height='200' rx='18' fill='oklch(0.8 0.07 15)'/%3E%3Crect x='120' y='200' width='160' height='200' rx='18' fill='url(%23sh)'/%3E%3Crect x='120' y='200' width='160' height='200' rx='18' fill='url(%23gls)'/%3E%3Cellipse cx='200' cy='214' rx='72' ry='10' fill='oklch(0.95 0.02 85)'/%3E%3Cpath d='M200 214 v-18' stroke='oklch(0.25 0.01 60)' stroke-width='3'/%3E%3Crect x='144' y='270' width='112' height='70' rx='4' fill='oklch(0.97 0.01 90)'/%3E%3Ctext x='200' y='302' text-anchor='middle' font-family='Georgia,serif' font-size='18' fill='oklch(0.3 0.02 60)'%3EFig Leaf%3C/text%3E%3Ctext x='200' y='322' text-anchor='middle' font-family='Arial,sans-serif' font-size='9' letter-spacing='2' fill='oklch(0.45 0.02 60)'%3EPLANT WAX %C2%B7 6.3 OZ%3C/text%3E%3C/svg%3E" alt=""><span class="mv-product-card-qty" aria-label="Quantity 2">2</span></div>
          <div class="mv-product-card-body"><p class="mv-product-card-title">Fig Leaf Scented Candle</p><p class="mv-product-card-meta">6.3 oz · Plant-based wax</p></div>
          <mv-price value="72" data-size="sm"></mv-price>
        </article>
      </mv-product-card>
      <mv-product-card data-title="Canvas Tote Bag" data-price="45">
        <article class="mv-product-card" data-variant="compact">
          <div class="mv-product-card-media"><img class="mv-product-card-image" src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 400 500'%3E%3Cdefs%3E%3ClinearGradient id='bg' x1='0' y1='0' x2='0' y2='1'%3E%3Cstop offset='0' stop-color='oklch(0.95 0.01 90)'/%3E%3Cstop offset='1' stop-color='oklch(0.87 0.02 85)'/%3E%3C/linearGradient%3E%3CradialGradient id='fl'%3E%3Cstop offset='0' stop-color='black' stop-opacity='.22'/%3E%3Cstop offset='1' stop-color='black' stop-opacity='0'/%3E%3C/radialGradient%3E%3ClinearGradient id='sh' x1='0' x2='1'%3E%3Cstop offset='0' stop-color='white' stop-opacity='.22'/%3E%3Cstop offset='.55' stop-color='white' stop-opacity='0'/%3E%3Cstop offset='1' stop-color='black' stop-opacity='.16'/%3E%3C/linearGradient%3E%3C/defs%3E%3Crect width='400' height='500' fill='url(%23bg)'/%3E%3Cellipse cx='200' cy='418' rx='140' ry='16' fill='url(%23fl)' opacity='1'/%3E%3Cpath d='M150 170 C150 100 250 100 250 170' fill='none' stroke='oklch(0.62 0.06 60)' stroke-width='12' stroke-linecap='round'/%3E%3Cpath d='M168 172 C168 118 232 118 232 172' fill='none' stroke='oklch(0.55 0.06 60)' stroke-width='10' stroke-linecap='round'/%3E%3Cpath d='M102 170 L298 170 L318 410 Q200 420 82 410 Z' fill='oklch(0.93 0.02 90)'/%3E%3Cpath d='M102 170 L298 170 L318 410 Q200 420 82 410 Z' fill='url(%23sh)'/%3E%3Crect x='140' y='150' width='20' height='40' rx='4' fill='oklch(0.55 0.06 60)'/%3E%3Crect x='240' y='150' width='20' height='40' rx='4' fill='oklch(0.55 0.06 60)'/%3E%3Ctext x='200' y='300' text-anchor='middle' font-family='Georgia,serif' font-size='30' letter-spacing='8' fill='black' fill-opacity='.55'%3ELUMEN%3C/text%3E%3Ctext x='200' y='326' text-anchor='middle' font-family='Arial,sans-serif' font-size='10' letter-spacing='4' fill='black' fill-opacity='.45'%3ESUPPLY CO %C2%B7 NYC%3C/text%3E%3Cpath d='M102 170 L298 170' stroke='black' stroke-opacity='.15' stroke-width='6'/%3E%3C/svg%3E" alt=""><span class="mv-product-card-qty" aria-label="Quantity 1">1</span></div>
          <div class="mv-product-card-body"><p class="mv-product-card-title">Canvas Tote Bag</p><p class="mv-product-card-meta">Ecru · Organic cotton</p></div>
          <mv-price value="45" data-size="sm"></mv-price>
        </article>
      </mv-product-card>
      <output id="pc-demo-log" aria-live="polite" style="min-height:1.25rem;font-size:.8125rem;color:var(--mv-fg-muted)"></output>
    </div>
  </section>
</div>
<script type="module">
  const root = document.getElementById("pc-demo");
  const log = root.querySelector("#pc-demo-log");
  const fmt = new Intl.NumberFormat("en-US", { style: "currency", currency: "USD" });
  root.addEventListener("mv-add", (e) => { log.textContent = `mv-add · ${e.detail.title}${e.detail.variant ? ` (${e.detail.variant})` : ""}`; });
  root.addEventListener("mv-quantity", (e) => { log.textContent = `mv-quantity · ${e.detail.title} × ${e.detail.quantity} = ${fmt.format(e.detail.total)}`; });
  root.addEventListener("mv-wishlist", (e) => { log.textContent = `mv-wishlist · ${e.detail.title} ${e.detail.pressed ? "added" : "removed"}`; });
  root.addEventListener("mv-remove", (e) => { log.textContent = `mv-remove · ${e.detail.title}`; });
</script>

API

Attributes

NameTipoDefaultDescription
data-id / data-title / data-price / data-compare-at / data-variantstring / numberOn <mv-product-card>: data passed along in events; data-price drives the line total.
added-textstringAdded to cartAdd-to-cart confirmation message.
data-varianthorizontal | compactOn .mv-product-card: cart line, or compact line (thumbnail + quantity badge). Vertical tile by default.
data-statesold-outOn .mv-product-card: desaturated image, quick add hidden.
data-altbooleanOn the 2nd .mv-product-card-image: shown on hover.
data-addstringOn a button: quick add; its value is the variant (size).
data-removebooleanOn a button: removes the line.
data-roletotal | unitRecalculated mv-price (price × quantity); the “each” note shows from 2 items.
data-tonesale | accent | darkOn .mv-product-card-badge.

Properties

NameTipoDescription
productobject{ id, title, price, compareAt, image, variant, quantity }.
quantity / lineTotalnumberQuantity (inner mv-quantity) and line total.

Methods

NameDescription
removeLine({ animate })Emits mv-remove (cancelable), collapses the line, then detaches it.

Events

NameDescription
mv-addCancelable; detail: product + { variant, quantity: 1 }.
mv-removeCancelable (preventDefault = the parent handles it, e.g. a cart with undo).
mv-quantitydetail: product + { quantity, total }.
mv-wishlistdetail: { id, title, pressed }.

Content structure

NameDescription
.mv-product-card-mediaImages, .mv-product-card-badges, mv-like.mv-product-card-wishlist, .mv-product-card-quick.
.mv-product-card-quickQuick-add panel: .mv-product-card-quick-title + .mv-product-card-sizes (data-add buttons) or .mv-product-card-quick-add.
.mv-product-card-body-vendor, -title > .mv-product-card-link (stretched link), mv-rating, mv-price, -colors, -subtitle; in a line: -head, -meta, -note, -actions.

CSS classes

NameDescription
mv-product-card / -media / -image / -badges / -badge / -wishlist / -quick / -quick-title / -sizes / -quick-add / -quick-toggle / -body / -vendor / -title / -link / -subtitle / -colors / -more / -head / -meta / -note / -actions / -remove / -remove-text / -qtyStructure.

CSS variables

NameDefaultDescription
--mv-product-card-ratio4 / 5Image aspect ratio.
--mv-product-card-radiusvar(--mv-radius-lg)Image radius.
--mv-product-card-thumb6remThumbnail width in the cart line.

Accessibility

A single stretched link (the title) covers the card; wishlist and quick add stay as buttons above it (z-index), reachable by keyboard: the quick-add panel opens on hover and as soon as one of its buttons has focus, and on touch screens via a “+” button (aria-expanded; Escape and outside click close it). Sold-out sizes are disabled and labeled “sold out”. Add, wishlist and removal are announced in a role=status region. The 2nd image is decorative (empty alt). Reduced motion: no zoom or animated collapse.

Esta página foi traduzida com IA. Informar um problema de tradução