> ## Documentation Index
> Fetch the complete documentation index at: https://docs-loja.usecorvex.com.br/llms.txt
> Use this file to discover all available pages before exploring further.

# Product Card

> Cookbook — card reutilizável de produto com snippet, resolução de dados e grid responsivo.

> Quero um card de produto reutilizável para grids e listagens. Qual é a implementação recomendada?

Referência: `seu tema (adaptado do cookbook)` + `sections/product-card/`

Índice: [Cookbooks](https://docs-loja.usecorvex.com.br/cookbook/overview.md)

***

## Contratos utilizados

* [Product Contract](https://docs-loja.usecorvex.com.br/reference/contracts/product.md) — **ProductSummary** (campos do card)
* [Section Contract](https://docs-loja.usecorvex.com.br/reference/contracts/section.md)
* [Snippet Contract](https://docs-loja.usecorvex.com.br/reference/contracts/snippet.md)
* [Data Contract](https://docs-loja.usecorvex.com.br/reference/contracts/data.md) — `defineSectionData`
* Field [`product_list`](https://docs-loja.usecorvex.com.br/schema/fields/product-list) — valor = `string[]` (UUID do produto)
* `@corvex/runtime` — [PUBLIC\_EDITOR\_INTEGRATION](https://docs-loja.usecorvex.com.br/reference/runtime-api.md): `SectionChrome` apenas

***

## Contrato de dados do Product Card (público)

Campos **oficialmente utilizáveis** no snippet (ProductSummary / Product):

| Campo | Uso no card |
| - | - |
| `id` | `key` em listas |
| `handle` | fallback interno da plataforma |
| `url` | `href` do link |
| `title` | nome exibido |
| `featuredImage.url` | imagem principal |
| `featuredImage.altText` | `alt` da imagem |
| `price.formatted` | preço de venda |
| `compareAtPrice.formatted` | preço riscado (quando promoção) |
| `availableForSale` | badge esgotado |

**Não usar** no card: `name` (deprecated), `stock`, `featured`, `reviewSummary` nem o objeto de preço cru da API. Use `title`, `availableForSale`, `price.formatted` e `featuredImage` do [contrato de produto](https://docs-loja.usecorvex.com.br/reference/contracts/product.md).

**Badge de promoção:** `compareAtPrice.amount > price.amount` (valores públicos `Money.amount`).

**Helpers SDK** (`getProductImage`, `getProductPrice`) existem mas fazem fallback em campos não públicos — este cookbook usa **somente** `featuredImage` e `price.formatted`.

***

## Separação de camadas

```text theme={"theme":{"light":"github-light","dark":"github-dark"}}
snippets/product-card/snippet.jsx     → UI pura (props: product)
sections/product-card/section.jsx     → schema + defineSectionData + grid
sections/product-card/schema.json     → settings do merchant
```

***

## Resolução de dados

`product_list` persiste UUIDs (`string[]`). Resolver com API pública:

```jsx theme={"theme":{"light":"github-light","dark":"github-dark"}}
export const data = defineSectionData(async ({ storefront, settings }) => {
  const refs = Array.isArray(settings.products)
    ? settings.products.filter(Boolean)
    : [];
  if (!refs.length) return { products: [] };

  const results = await Promise.all(
    refs.map(async (ref) => {
      try {
        return await storefront.products.get(ref);
      } catch {
        return null;
      }
    })
  );
  return { products: results.filter(Boolean) };
});
```

`storefront.products.get(ref)` aceita id ou handle (API pública `StorefrontClient`).

**Loading:** a runtime injeta `data` quando o loader termina; até então a section pode não renderizar (wrapper `withSectionData`). Empty/error são tratados na section com mensagens explícitas.

***

## Snippet (UI)

```jsx theme={"theme":{"light":"github-light","dark":"github-dark"}}
import ProductCard from '@corvex/snippets/product-card';

<ProductCard
  product={product}
  showSaleBadge={true}
  saleBadgeLabel="Promoção"
  outOfStockLabel="Esgotado"
/>
```

* Link envolve o card (`product.url`)
* Fallback visual sem `featuredImage`
* Compare-at e badge só quando `compareAtPrice` > `price`
* `availableForSale === false` → badge esgotado (sem CTA de carrinho neste cookbook)

***

## Section (grid responsivo)

Settings: `title`, `products` (`product_list`), `showSaleBadge`, `saleBadgeLabel`, `columns` (2–4 desktop).

CSS: grid 2 colunas mobile; `columns` via `--product-card-columns` em breakpoint `640px+`.

***

## Estados

| Estado | UI |
| - | - |
| Sem seleção | "Selecione produtos no inspector." |
| Seleção sem resolução | "Nenhum produto encontrado…" |
| Produtos resolvidos | Grid de cards |
| Produto indisponível | Badge no card (`availableForSale`) |

***

## Checklist

* [ ] Snippet importado via `@corvex/snippets/product-card`
* [ ] Resolução com `storefront.products.get` (não inventar fetch)
* [ ] Somente campos ProductSummary públicos
* [ ] Sem hooks de editor no snippet
* [ ] `corvex validate .`

O card não adiciona ao carrinho. Variante e compra: [Seletor de variante](https://docs-loja.usecorvex.com.br/cookbook/variant-selector.md). Carrinho: [Drawer](https://docs-loja.usecorvex.com.br/cookbook/cart-drawer.md).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.