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

# Templates personalizados

> Substitua a renderização de qualquer bloco do Aftersell Cart pelo seu próprio JSX: o que um template substitui, o que está no escopo, como estilizá-lo e onde encontrar as props de cada bloco.

Um **template personalizado** permite substituir a forma como um bloco individual é renderizado. Em vez da interface nativa do bloco, o carrinho renderiza seu próprio JSX, usando os mesmos dados que o bloco normalmente usaria. É uma capacidade transversal, e não um bloco por si só: a maioria dos blocos a expõe pela sua aba **Code**.

Esta página cobre o que se aplica a **todos** os blocos. Para as props que um bloco específico entrega a você, vá para [a referência do próprio bloco](#props-for-each-block).

<div id="custom-template-vs-custom-code-block">
  ## Template personalizado vs. bloco Custom code
</div>

Eles soam parecidos, mas fazem coisas diferentes:

* Um **template personalizado** *substitui a renderização de um bloco existente* pela sua própria marcação e entrega a você os dados daquele bloco (o título e a contagem de itens do Header, os totais do Summary e assim por diante). Ele não adiciona nada novo; ele reestiliza um bloco.
* O bloco **[Custom code](/pt/aftersell/cart/custom-code-blocks)** *adiciona um novo bloco* de HTML ou React arbitrário em qualquer lugar do carrinho.

Recorra a um template personalizado quando o bloco nativo está quase certo, mas você precisa de um layout ou marcação diferente. Recorra a um bloco Custom code quando quiser adicionar algo que os blocos nativos não cobrem.

<div id="using-a-custom-template">
  ## Usando um template personalizado
</div>

1. Selecione um bloco no editor e abra sua aba **Code**.
2. Edite o template padrão. Templates personalizados são **somente JSX** (a escolha entre HTML ou JSX é exclusiva do bloco Custom code).
3. Clique em **Compile**. Compilar remove os tipos e transpila o JSX, então captura erros de **sintaxe**. Erros de tipo não impedem a compilação — o editor os marca inline conforme você digita, com o mesmo IntelliSense que faz autocompletar das props do bloco.
4. Ative o template para que o carrinho o use em vez da renderização nativa.
5. **Reset to default** restaura o template original do bloco a qualquer momento.

<div id="writing-a-template-with-ai">
  ## Escrevendo um template com IA
</div>

A aba Code inclui um botão **Copy AI prompt** (ícone de varinha ✦). Clicar nele copia para a sua área de transferência um briefing autocontido que você pode colar diretamente em uma sessão de chat de IA (Claude, ChatGPT ou similar).

O prompt inclui tudo o que a IA precisa para escrever um template válido para aquele bloco específico:

* As regras de compilação (expressão única, sem `export default`, sem imports)
* As props exatas que o bloco recebe, correspondendo ao que o IntelliSense do editor mostra
* A assinatura de função travada que o editor impõe
* Regras específicas do bloco (formatos de dinheiro, quais handlers conectar, requisitos de acessibilidade)
* Uma seção para preencher, onde você cola seu template atual e descreve a mudança que quer

Depois de copiar, abra uma sessão de IA, cole o prompt, preencha os dois espaços em branco no final (seu template atual e a mudança que você quer) e envie. A IA retorna um template completo que você pode colar de volta no editor e compilar.

<Tip>
  Cole seu template existente na seção de preenchimento em vez de deixá-la em branco. A IA o usa como ponto de partida, então qualquer personalização que você já fez é levada adiante em vez de ser substituída pelo padrão.
</Tip>

<Note>
  O prompt é específico de cada bloco. O botão **Copy AI prompt** só aparece em blocos que suportam templates personalizados.
</Note>

<Tip>
  O template padrão do qual você parte é uma **cópia funcional da marcação nativa do bloco**, então você sempre tem uma referência correta e renderizável para modificar, em vez de uma página em branco. Recorra a **Reset to default** sempre que quiser essa referência de volta.

  Nem sempre é uma correspondência byte a byte. O template padrão do Header também renderiza `logoUrl`, para o qual a marcação nativa não tem posicionamento, então ativar esse template é a forma como uma imagem de cabeçalho enviada aparece pela primeira vez.
</Tip>

<div id="what-your-template-replaces">
  ## O que seu template substitui
</div>

Um template substitui a renderização do bloco **por completo**. Não sobra nenhum wrapper ao redor do seu JSX, o que tem consequências que vale conhecer antes de começar a apagar coisas:

| Você perde                                  | O que isso significa                                                                                                                                                                             |
| ------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| O elemento wrapper do bloco                 | Nada envolve sua marcação. Qualquer padding, alinhamento ou layout que o bloco fornecia agora é responsabilidade sua.                                                                            |
| **As configurações da aba Design do bloco** | As configurações de design são aplicadas como estilos inline no wrapper nativo, e esse wrapper se foi. Cores, espaçamento e raios definidos na aba Design **deixam de se aplicar** a este bloco. |
| Recursos de acessibilidade nativos          | `aria-label`s, gerenciamento de foco e elementos semânticos só existem se o seu JSX os incluir.                                                                                                  |

<Warning>
  **A aba Design é a que pega as pessoas de surpresa.** Enquanto um template personalizado está ativo, os campos da aba Design ficam desativados e um ícone de aviso aparece ao lado do título "Design". Passe o mouse sobre o ícone para ver o motivo. Estilize o bloco a partir do seu template, seja [inline ou com seu próprio CSS](#styling-a-custom-template). Os campos são reativados assim que você desativa o template personalizado.
</Warning>

O que você mantém: a posição do bloco no carrinho, seu botão de visibilidade, suas configurações (que continuam alimentando as props que você recebe), o painel de [Custom CSS](/pt/aftersell/cart/custom-css) do carrinho e **o skeleton de carregamento nativo**.

Esse último surpreende as pessoas. O bloco verifica se o carrinho ainda está carregando *antes* de chegar ao seu template, então o skeleton nativo é renderizado durante o carregamento e seu template só executa quando o carrinho está pronto. Você não precisa construir um estado de carregamento.

<div id="whats-available-inside-a-template">
  ## O que está disponível dentro de um template
</div>

Seu template é um único componente de função. Ele compila a partir de **TSX**, então anotações de tipo são permitidas e removidas na compilação. É por isso que os templates padrão são escritos com elas:

```jsx theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
function Header(props: HeaderProps) {
  return <div>{/* … */}</div>;
}
```

**A linha da assinatura e a chave de fechamento são travadas** — o editor não deixa você editar nenhuma delas, e ao passar o mouse aparece "Locked — this line can't be edited." Você escreve o corpo entre elas. **Reset to default** é a única coisa que pode substituí-las.

O que mais importa:

* **Você tem cinco hooks:** `useState`, `useEffect`, `useMemo`, `useRef` e `useCallback`. Mais `Fragment`, para `<>…</>`.
* **Não há imports.** Você não pode fazer `import` de nada, e não há objeto `React` no escopo, então nada de `React.useReducer` nem `React.Children`. Se um hook não está na lista acima, ele não está disponível.
* **As props são somente leitura.** Mutar uma prop não vai fazer nada útil. Para alterar o carrinho, use as props de handler que o bloco fornece (`onClose`, `increment`, `selectPlan` e assim por diante) em vez de escrever nas props diretamente.
* **`window` é alcançável**, então um template pode chamar o [Cart SDK](/pt/aftersell/cart/sdk-overview) via `window.aftersell.cart` quando precisa de algo que as props do bloco não cobrem.

<div id="conventions-across-every-block">
  ## Convenções em todos os blocos
</div>

Três regras valem em todo lugar, e conhecê-las elimina a maior parte das adivinhações:

* **Props `*Html` são rich text pré-sanitizado.** Renderize-as com `dangerouslySetInnerHTML`. Elas já passaram pelo sanitizador do carrinho, e tokens do lojista como `{{total_price}}` já estão resolvidos.
* **Preços que chegam como `string` já estão formatados** no formato de dinheiro da loja. Preços como `number` estão em centavos. Um bloco fornece um ou outro, e a tabela de cada bloco diz qual.
* **`isLoading` é sempre `false` dentro de um template.** O bloco renderiza seu skeleton nativo e só chama seu template quando o carrinho carregou, então a prop é passada por completude, não para você ramificar sobre ela.

<Note>
  Alguns blocos não retornam nada em certos estados, então seu template nunca é chamado com dados vazios. O template do Rewards nunca vê um `milestones` vazio, e o template do Subscription upgrade nunca vê um `view` nulo. A referência de cada bloco indica onde isso se aplica, para que você possa pular a ramificação de estado vazio.
</Note>

<div id="styling-a-custom-template">
  ## Estilizando um template personalizado
</div>

O template padrão do qual você parte carrega os nomes de classe do bloco. Como você estiliza suas edições depende de quão longe você vai desse ponto de partida.

<div id="the-two-class-families">
  ### As duas famílias de classes
</div>

Todo elemento em um template padrão carrega um nome de classe pareado, e eles fazem trabalhos muito diferentes:

| Família           | O que faz                                                                                                              | Escrever CSS contra ela?                                                                     |
| ----------------- | ---------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------- |
| `cart-internal-*` | **Carrega a estilização nativa do bloco.** Toda regra da folha de estilos do carrinho mira essa família.               | Não. É a estrutura interna do carrinho, e o editor de Custom CSS marca seletores contra ela. |
| `cart-external-*` | **Um gancho sem estilização própria.** Nada na folha de estilos do carrinho a mira; ela existe para o seu CSS agarrar. | Sim. Essa é a forma suportada de reestilizar um bloco.                                       |

Então `cart-internal-header__title` é o que faz o título *parecer* com o título nativo, e `cart-external-header__title` é a alça que você deve agarrar quando quer mudar sua aparência.

<div id="small-changes-keep-both-classnames">
  ### Mudanças pequenas: mantenha os dois nomes de classe
</div>

Se você está reordenando elementos, mudando rótulos ou adicionando algo dentro da estrutura existente, deixe os nomes de classe em paz. Você mantém o visual nativo de graça e reestiliza pelo [Custom CSS](/pt/aftersell/cart/custom-css) mirando os ganchos `cart-external-*`.

<div id="restructuring-drop-both-classnames">
  ### Reestruturação: descarte os dois nomes de classe
</div>

Quando você está mudando a estrutura DOM em vez de ajustá-la, retire **ambas** as famílias da sua marcação e use [seus próprios nomes de classe](#option-1-your-own-classnames-plus-custom-css) em vez disso. Há um motivo distinto para cada uma.

**Descarte `cart-internal-*` porque o CSS nativo foi escrito para o DOM nativo.** Mantenha essas classes em uma marcação reestruturada e você herda regras de layout que pressupõem elementos que você não tem mais: contêineres flex esperando filhos diferentes, espaçamento entre elementos que se moveram, posicionamento relativo a algo que você removeu. Isso geralmente aparece como o seu próprio CSS "não funcionando" quando as regras nativas são as que estão vencendo.

<Warning>
  **Descarte `cart-external-*` porque é um nome compartilhado, não seu.** Esses nomes de classe significam algo específico na marcação nativa, e seu Custom CSS é escrito uma única vez para o carrinho inteiro. Se um template reestruturado os reutiliza, qualquer regra que você escrever mira tanto a sua estrutura quanto a nativa.

  Isso dá errado no momento em que você desativa o template personalizado: o bloco reverte à marcação nativa, e seu CSS continua apontando para ela, agora estilizando um DOM para o qual nunca foi escrito. Um prefixo próprio mantém os dois claramente separados, para que desativar um template seja uma reversão limpa.
</Warning>

Duas formas de estilizar o que você construiu:

<div id="option-1-your-own-classnames-plus-custom-css">
  #### Opção 1: seus próprios nomes de classe mais Custom CSS
</div>

Melhor para qualquer coisa que você vai manter ou reutilizar. Dê às suas classes um prefixo com o qual ninguém mais vai colidir, geralmente o nome da sua loja ou marca:

```jsx theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
function Header(props) {
  return (
    <div className="northwind-custom-header">
      <div className="northwind-custom-header__title" dangerouslySetInnerHTML={{ __html: props.title }} />
      <button type="button" className="northwind-custom-header__close" onClick={props.onClose}>
        &times;
      </button>
    </div>
  );
}
```

Depois, no Cart Editor, selecione **Cart settings** no painel esquerdo e abra a aba **Custom CSS** à direita:

```css theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
.northwind-custom-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 16px;
}

.northwind-custom-header__title {
  font-size: 18px;
  font-weight: 600;
}

.northwind-custom-header__close:hover {
  opacity: 0.6;
}
```

Um prefixo importa mais do que parece. Sem um, uma classe como `.header` ou `.title` corre o risco de colidir com as classes do próprio carrinho, com o template de outro app ou com um bloco futuro.

<div id="option-2-inline-styles">
  #### Opção 2: estilos inline
</div>

Sem ida e volta ao painel de CSS, e tudo fica em um único lugar:

```jsx theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
<div style={{ display: 'flex', alignItems: 'center', gap: '12px' }}>
```

Bom para estrutura de layout e casos pontuais. Seus limites são os habituais: sem `:hover` ou outras pseudoclasses, sem media queries e sem reutilização entre blocos. Recorra à Opção 1 quando quiser qualquer uma dessas coisas.

<div id="picking-an-approach">
  ### Escolhendo uma abordagem
</div>

| Situação                                         | Faça isto                                                                                                       |
| ------------------------------------------------ | --------------------------------------------------------------------------------------------------------------- |
| Mesma estrutura, texto ou ordem diferente        | Mantenha os dois nomes de classe, reestilize via Custom CSS em `cart-external-*`                                |
| Nova estrutura, estilização que você vai manter  | Suas próprias classes com prefixo, ambas as famílias do carrinho descartadas                                    |
| Nova estrutura, algumas regras rápidas de layout | Estilos inline, ambas as famílias do carrinho descartadas                                                       |
| Muito código personalizado em vários blocos      | Suas próprias classes com prefixo em todo lugar, para que qualquer template possa ser desativado de forma limpa |

<Note>
  O carrinho é renderizado em um shadow root, então a folha de estilos do seu tema não consegue alcançar seu interior. Os estilos de um template personalizado precisam vir do painel **Custom CSS** do próprio carrinho ou de estilos inline, não do seu tema. Veja [CSS personalizado](/pt/aftersell/cart/custom-css).
</Note>

<div id="when-a-template-fails">
  ## Quando um template falha
</div>

Um template quebrado nunca quebra o carrinho. O bloco renderiza **nada** e tudo ao redor continua funcionando, o que é seguro mas fácil de passar despercebido: um espaço em branco onde seu bloco deveria estar é o sintoma.

| Falha                           | Quando você vai ver              | Onde é reportada                                                                                                        |
| ------------------------------- | -------------------------------- | ----------------------------------------------------------------------------------------------------------------------- |
| Erro de tipo                    | Enquanto você digita             | Um sublinhado inline no editor. Ele **não** bloqueia a compilação — o compilador remove os tipos em vez de verificá-los |
| Erro de sintaxe                 | Quando você clica em **Compile** | No editor, antes de poder chegar à sua loja                                                                             |
| Um crash durante a renderização | Na loja, quando está no ar       | `console.error('[aftersell-cart] module crashed: …')`                                                                   |

Como o bloco desaparece silenciosamente em vez de mostrar um erro visível, sempre verifique um template na [pré-visualização](/pt/aftersell/cart/previewing-carts) antes de publicar. Se um bloco sumiu, abra o console do navegador primeiro.

Duas coisas que vale a pena proteger, já que ambas quebram um template que pressupõe o contrário:

* **Props anuláveis.** Muitas props são `null` em condições normais (`logoUrl` sem logo, `imageUrl` sem imagem, `variantTitle` em um produto de variante única). Verifique antes de usá-las.
* **Arrays que podem estar vazios.** `discountTags` e `discountCodes` são `[]` na maioria das vezes.

<div id="limitations">
  ## Limitações
</div>

* **Templates personalizados são substituições de exibição.** Para executar lógica no carrinho (assinar eventos, adicionar itens, reagir a mudanças), use [Scripts personalizados](/pt/aftersell/cart/custom-scripts) e o [Cart SDK](/pt/aftersell/cart/sdk-overview).
* **Quase todo bloco suporta um.** As exceções são o bloco **[Express payments](/pt/aftersell/cart/express-payments-block)**, que hospeda os botões de pagamento da própria Shopify, e o contêiner **[Cart items](/pt/aftersell/cart/cart-items-block)** em si, embora a linha **Product** dentro dele suporte um template personalizado.
* **Um template não pode mudar o que um bloco fundamentalmente faz.** Ele muda como os dados do bloco são apresentados, não os dados ou o comportamento por trás deles.

<div id="props-for-each-block">
  ## Props de cada bloco
</div>

Cada bloco passa seus próprios dados. A tabela completa de props, com tipos e um exemplo trabalhado, fica na página daquele bloco:

| Bloco                                                                                 | Props que recebe                                                                                                                   |
| ------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| [Header](/pt/aftersell/cart/header-block#custom-template)                             | `title`, `logoUrl`, `leftSection`, `rightSection`, `itemCount`, `onClose`, `isLoading`                                             |
| [Banner](/pt/aftersell/cart/banner-block#custom-template)                             | `text`, `shouldUseTimer`, `isTimerExpiredAndShouldHide`, `isLoading`                                                               |
| [Rewards](/pt/aftersell/cart/rewards-block#custom-template)                           | `milestones`, `rewardsMessageHtml`, `showIcons`, `isLoading`                                                                       |
| [Cart items · Product](/pt/aftersell/cart/cart-items-block#custom-template)           | 25 props: conteúdo por linha, identificadores e controles de quantidade                                                            |
| [Subscription upgrade](/pt/aftersell/cart/subscription-upgrade-block#custom-template) | `view`, `selectPlan`, `onChange`, `oneTimeValue` e mais                                                                            |
| [Summary](/pt/aftersell/cart/summary-block#custom-template)                           | `leftHtml`, `rightHtml`, `discountCodes`, `totalPrice`, `savings` e mais                                                           |
| [Checkout button](/pt/aftersell/cart/checkout-button-block#custom-template)           | `label`, `href`, `isLoading`                                                                                                       |
| [Discount code](/pt/aftersell/cart/discount-code-block#custom-template)               | `discountCodeInput`, `placeholder`, `buttonText`, `isValidating`, `isInvalid`, `setDiscountCodeInput`, `handleSubmit`, `isLoading` |
| [Empty cart](/pt/aftersell/cart/empty-cart-block#custom-template)                     | `text`, `cta`, `href`                                                                                                              |
| [Image](/pt/aftersell/cart/image-block#custom-template)                               | `imageUrl`, `altText`, `maxHeight`, `fullWidth`                                                                                    |
| [Notes](/pt/aftersell/cart/notes-block#custom-template)                               | `titleHtml`, `placeholder`, `noteInput`, `status`, `isExpanded`, `onNoteChange`, `onNoteBlur`, `onToggle` e mais                   |
| [Product add-on](/pt/aftersell/cart/product-add-on-block#custom-template)             | `addonTitleHtml`, `descriptionHtml`, `priceHtml`, `imageUrl`, `format`, `isEnabled`, `handleAdd`, `handleToggle` e mais            |
| [Shipping protection](/pt/aftersell/cart/shipping-protection-block#custom-template)   | `titleHtml`, `descriptionHtml`, `priceHtml`, `imageUrl`, `format`, `isEnabled`, `handleAdd`, `handleToggle` e mais                 |
| [Upsells](/pt/aftersell/cart/upsells-block#custom-template)                           | `title`, `addButtonText`, `layout`, `upsells`, `selectVariant`, `handleAdd` e os controles do carrossel                            |

O bloco [Custom code](/pt/aftersell/cart/custom-code-blocks) é a única superfície que **adiciona** marcação em vez de substituir a renderização de um bloco, então suas props são diferentes: o carrinho inteiro, mais uma ação de adicionar ao carrinho. Veja [Blocos Custom code → Props](/pt/aftersell/cart/custom-code-blocks#props).
