> ## 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.

# Aangepaste templates

> Overschrijf hoe elk Aftersell Cart-blok rendert met je eigen JSX: wat een template vervangt, wat er beschikbaar is, hoe je het stylet en waar je de props van elk blok vindt.

Met een **aangepaste template** kun je overschrijven hoe een individueel blok rendert. In plaats van de ingebouwde UI van het blok rendert de cart jouw eigen JSX, met dezelfde gegevens die het blok normaal zou gebruiken. Het is een overkoepelende mogelijkheid in plaats van een eigen blok: de meeste blokken bieden het aan via hun tabblad **Code**.

Deze pagina behandelt wat voor **elk** blok geldt. Voor de props die een specifiek blok je geeft, ga je naar [de eigen referentie van het blok](#props-for-each-block).

<div id="custom-template-vs-custom-code-block">
  ## Aangepaste template versus Custom code-blok
</div>

Deze klinken vergelijkbaar maar doen verschillende dingen:

* Een **aangepaste template** *vervangt de rendering van een bestaand blok* door je eigen markup, en geeft je de eigen gegevens van dat blok (de titel en het aantal items van de Header, de totalen van de Summary, enzovoort). Het voegt niets nieuws toe; het herstylet één blok.
* Het **[Custom code](/nl/aftersell/cart/custom-code-blocks)**-blok *voegt een nieuw blok toe* met willekeurige HTML of React, overal in de cart.

Grijp naar een aangepaste template wanneer het ingebouwde blok bijna goed is maar je een andere lay-out of markup nodig hebt. Grijp naar een Custom code-blok wanneer je iets wilt toevoegen dat de ingebouwde blokken niet dekken.

<div id="using-a-custom-template">
  ## Een aangepaste template gebruiken
</div>

1. Selecteer een blok in de editor en open het tabblad **Code**.
2. Bewerk de standaardtemplate. Aangepaste templates zijn **alleen JSX** (de keuze tussen HTML en JSX is exclusief voor het Custom code-blok).
3. Klik op **Compile**. Compileren verwijdert de types en transpileert de JSX, dus het vangt **syntaxfouten** af. Typefouten stoppen een compile niet — de editor markeert die inline terwijl je typt, met dezelfde IntelliSense die de props van het blok automatisch aanvult.
4. Zet de template aan zodat de cart deze gebruikt in plaats van de ingebouwde rendering.
5. **Reset to default** herstelt op elk moment de oorspronkelijke template van het blok.

<div id="writing-a-template-with-ai">
  ## Een template schrijven met AI
</div>

Het Code-tabblad bevat een knop **Copy AI prompt** (✦ toverstaf-icoon). Erop klikken kopieert een op zichzelf staande briefing naar je klembord die je direct in een AI-chatsessie kunt plakken (Claude, ChatGPT of vergelijkbaar).

De prompt bevat alles wat de AI nodig heeft om een geldige template voor dat specifieke blok te schrijven:

* De compileregels (één expressie, geen `export default`, geen imports)
* De exacte props die het blok ontvangt, overeenkomend met wat de IntelliSense van de editor toont
* De vergrendelde functiesignatuur die de editor afdwingt
* Blokspecifieke regels (geldformaten, welke handlers je moet koppelen, toegankelijkheidsvereisten)
* Een invulsectie waar je je huidige template plakt en de gewenste wijziging beschrijft

Na het kopiëren open je een AI-sessie, plak je de prompt, vul je de twee lege velden onderaan in (je huidige template en de gewenste wijziging) en verstuur je hem. De AI geeft een complete template terug die je terug in de editor kunt plakken en compileren.

<Tip>
  Plak je bestaande template in de invulsectie in plaats van deze leeg te laten. De AI gebruikt hem als startpunt, zodat elke aanpassing die je al hebt gedaan wordt meegenomen in plaats van vervangen door de standaard.
</Tip>

<Note>
  De prompt is specifiek per blok. De knop **Copy AI prompt** verschijnt alleen op blokken die aangepaste templates ondersteunen.
</Note>

<Tip>
  De standaardtemplate waarmee je begint is een **werkende kopie van de ingebouwde markup van het blok**, dus je hebt altijd een correcte, renderende referentie om aan te passen in plaats van een lege pagina. Grijp naar **Reset to default** wanneer je die referentie terug wilt.

  Het is niet altijd een byte-voor-byte-match. De standaardtemplate van de Header rendert ook `logoUrl`, waarvoor de ingebouwde markup geen plek heeft, dus het inschakelen van die template is hoe een geüploade headerafbeelding voor het eerst verschijnt.
</Tip>

<div id="what-your-template-replaces">
  ## Wat je template vervangt
</div>

Een template vervangt de rendering van het blok **volledig**. Er blijft geen wrapper rond je JSX over, wat gevolgen heeft die je moet kennen voordat je dingen gaat verwijderen:

| Je verliest                                             | Wat dat betekent                                                                                                                                                                                                             |
| ------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Het wrapper-element van het blok                        | Niets omhult je markup. Alle padding, uitlijning of lay-out die het blok bood, moet je nu zelf leveren.                                                                                                                      |
| **De instellingen van het Design-tabblad van het blok** | Designinstellingen worden toegepast als inline styles op de ingebouwde wrapper, en die wrapper is weg. Kleuren, spacing en afrondingen die in het Design-tabblad zijn ingesteld, **worden niet meer toegepast** op dit blok. |
| Ingebouwde toegankelijkheidsvoorzieningen               | `aria-label`s, focusafhandeling en semantische elementen bestaan alleen als je JSX ze bevat.                                                                                                                                 |

<Warning>
  **Het Design-tabblad is degene waar mensen door worden verrast.** Terwijl een aangepaste template actief is, zijn de velden van het Design-tabblad uitgeschakeld en verschijnt er een waarschuwingsicoon naast de kop "Design". Beweeg over het icoon om te zien waarom. Style het blok in plaats daarvan vanuit je template, [inline of met je eigen CSS](#styling-a-custom-template). De velden worden weer ingeschakeld zodra je de aangepaste template uitzet.
</Warning>

Wat je behoudt: de positie van het blok in de cart, de zichtbaarheidsschakelaar, de instellingen (die nog steeds de props voeden die je ontvangt), het [Custom CSS](/nl/aftersell/cart/custom-css)-paneel van de cart, en **de ingebouwde laad-skeleton**.

Dat laatste verrast mensen. Het blok controleert of de cart nog aan het laden is *voordat* het je template bereikt, dus de ingebouwde skeleton rendert tijdens het laden en je template draait pas zodra de cart klaar is. Je hoeft geen laadstatus te bouwen.

<div id="whats-available-inside-a-template">
  ## Wat er beschikbaar is binnen een template
</div>

Je template is één functiecomponent. Deze compileert vanuit **TSX**, dus typeannotaties zijn toegestaan en worden bij het compileren verwijderd. Daarom zijn de standaardtemplates ermee geschreven:

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

**De signatuurregel en de sluitende accolade zijn vergrendeld** — de editor laat je geen van beide bewerken, en eroverheen bewegen toont "Locked — this line can't be edited." Je schrijft de body ertussen. **Reset to default** is het enige dat ze kan vervangen.

Wat verder van belang is:

* **Je krijgt vijf hooks:** `useState`, `useEffect`, `useMemo`, `useRef` en `useCallback`. Plus `Fragment`, voor `<>…</>`.
* **Er zijn geen imports.** Je kunt niets `import`en, en er is geen `React`-object beschikbaar, dus geen `React.useReducer`, geen `React.Children`. Als een hook niet in de bovenstaande lijst staat, is hij niet beschikbaar.
* **Props zijn alleen-lezen.** Een prop muteren doet niets nuttigs. Om de cart te wijzigen, gebruik je de handler-props die het blok je geeft (`onClose`, `increment`, `selectPlan`, enzovoort) in plaats van direct naar props te schrijven.
* **`window` is bereikbaar**, dus een template kan de [Cart SDK](/nl/aftersell/cart/sdk-overview) aanroepen via `window.aftersell.cart` wanneer het iets nodig heeft dat de props van het blok niet dekken.

<div id="conventions-across-every-block">
  ## Conventies voor elk blok
</div>

Drie regels gelden overal, en ze kennen neemt het meeste giswerk weg:

* **`*Html`-props zijn vooraf gesaneerde rich text.** Render ze met `dangerouslySetInnerHTML`. Ze zijn al door de sanitizer van de cart gegaan, en merchant-tokens zoals `{{total_price}}` zijn al ingevuld.
* **Prijzen die als `string` binnenkomen, zijn al geformatteerd** in het geldformaat van de winkel. Prijzen als `number` zijn in centen. Een blok geeft je het een of het ander, en de tabel van elk blok vermeldt welke.
* **`isLoading` is altijd `false` binnen een template.** Het blok rendert zijn ingebouwde skeleton en roept je template pas aan zodra de cart is geladen, dus de prop wordt voor de volledigheid meegegeven en niet om op te vertakken.

<Note>
  Een paar blokken renderen in bepaalde statussen helemaal niets, zodat je template nooit met lege data wordt aangeroepen. De Rewards-template ziet nooit een lege `milestones`, en de Subscription upgrade-template ziet nooit een null `view`. De referentie van elk blok vermeldt waar dit van toepassing is, zodat je de lege-status-vertakking kunt overslaan.
</Note>

<div id="styling-a-custom-template">
  ## Een aangepaste template stylen
</div>

De standaardtemplate waarmee je begint, draagt de classnames van het blok. Hoe je je bewerkingen stylet, hangt af van hoe ver je van dat startpunt afwijkt.

<div id="the-two-class-families">
  ### De twee class-families
</div>

Elk element in een standaardtemplate draagt een gepaarde classname, en ze doen heel verschillende dingen:

| Familie           | Wat het doet                                                                                                                       | CSS ertegen schrijven?                                                                             |
| ----------------- | ---------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- |
| `cart-internal-*` | **Draagt de ingebouwde styling van het blok.** Elke regel in de stylesheet van de cart target deze familie.                        | Nee. Het is het interne raderwerk van de cart, en de Custom CSS-editor markeert selectors ertegen. |
| `cart-external-*` | **Een haakje zonder eigen styling.** Niets in de stylesheet van de cart target het; het bestaat zodat jouw CSS het kan vastpakken. | Ja. Dit is de ondersteunde manier om een blok te herstylen.                                        |

Dus `cart-internal-header__title` is wat de titel eruit laat *zien* als de ingebouwde titel, en `cart-external-header__title` is het handvat dat je moet vastpakken wanneer je het uiterlijk wilt veranderen.

<div id="small-changes-keep-both-classnames">
  ### Kleine wijzigingen: behoud beide classnames
</div>

Als je elementen herschikt, herlabelt of iets toevoegt binnen de bestaande structuur, laat de classnames dan met rust. Je behoudt de ingebouwde look gratis, en je herstylet via [Custom CSS](/nl/aftersell/cart/custom-css) gericht op de `cart-external-*`-haakjes.

<div id="restructuring-drop-both-classnames">
  ### Herstructureren: laat beide classnames vallen
</div>

Zodra je de DOM-structuur verandert in plaats van bijstelt, haal je **beide** families van je markup en gebruik je in plaats daarvan [je eigen classnames](#option-1-your-own-classnames-plus-custom-css). Voor elk is er een aparte reden.

**Laat `cart-internal-*` vallen omdat de ingebouwde CSS voor de ingebouwde DOM is geschreven.** Houd die classes op geherstructureerde markup en je erft lay-outregels die uitgaan van elementen die je niet meer hebt: flex-containers die andere kinderen verwachten, spacing tussen verplaatste elementen, positionering ten opzichte van iets dat je hebt verwijderd. Dit uit zich meestal als je eigen CSS die "niet werkt" terwijl de ingebouwde regels winnen.

<Warning>
  **Laat `cart-external-*` vallen omdat het een gedeelde naam is, niet die van jou.** Die classnames betekenen iets specifieks op de ingebouwde markup, en je Custom CSS wordt één keer geschreven voor de hele cart. Als een geherstructureerde template ze hergebruikt, target elke regel die je schrijft zowel jouw structuur als de ingebouwde.

  Dat gaat mis zodra je de aangepaste template uitzet: het blok valt terug op zijn ingebouwde markup, en je CSS wijst er nog steeds naar en stylet nu een DOM waarvoor hij nooit is geschreven. Je eigen prefix houdt de twee netjes gescheiden, zodat een template uitzetten een schone terugkeer is.
</Warning>

Twee manieren om te stylen wat je hebt gebouwd:

<div id="option-1-your-own-classnames-plus-custom-css">
  #### Optie 1: je eigen classnames plus Custom CSS
</div>

Het beste voor alles wat je gaat onderhouden of hergebruiken. Geef je classes een prefix waar niemand anders mee botst, meestal je winkel- of merknaam:

```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>
  );
}
```

Selecteer vervolgens in de cart-editor **Cart settings** in het linkerpaneel en open het tabblad **Custom CSS** rechts:

```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;
}
```

Een prefix is belangrijker dan hij lijkt. Zonder prefix riskeert een class als `.header` of `.title` een botsing met de eigen classes van de cart, de template van een andere app of een toekomstig blok.

<div id="option-2-inline-styles">
  #### Optie 2: inline styles
</div>

Geen heen-en-weer naar het CSS-paneel, en alles staat op één plek:

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

Goed voor lay-outopbouw en eenmalige gevallen. De beperkingen zijn de gebruikelijke: geen `:hover` of andere pseudo-classes, geen media queries, en geen hergebruik over blokken heen. Grijp naar Optie 1 zodra je een van die dingen wilt.

<div id="picking-an-approach">
  ### Een aanpak kiezen
</div>

| Situatie                                          | Doe dit                                                                            |
| ------------------------------------------------- | ---------------------------------------------------------------------------------- |
| Zelfde structuur, andere tekst of volgorde        | Behoud beide classnames, herstyle via Custom CSS op `cart-external-*`              |
| Nieuwe structuur, styling die je gaat onderhouden | Je eigen geprefixte classes, beide cart-families weggelaten                        |
| Nieuwe structuur, een paar snelle lay-outregels   | Inline styles, beide cart-families weggelaten                                      |
| Veel aangepaste code over meerdere blokken        | Overal je eigen geprefixte classes, zodat elke template schoon kan worden uitgezet |

<Note>
  De cart rendert in een shadow root, dus de stylesheet van je thema kan er niet in reiken. Styles voor een aangepaste template moeten komen van het eigen **Custom CSS**-paneel van de cart of van inline styles, niet van je thema. Zie [Aangepaste CSS](/nl/aftersell/cart/custom-css).
</Note>

<div id="when-a-template-fails">
  ## Wanneer een template faalt
</div>

Een kapotte template breekt nooit de cart. Het blok rendert **niets** en alles eromheen blijft werken, wat veilig is maar makkelijk te missen: een lege plek waar je blok zou moeten staan, is het symptoom.

| Fout                           | Wanneer je hem ziet             | Waar hij wordt gemeld                                                                                                                      |
| ------------------------------ | ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
| Typefout                       | Terwijl je typt                 | Een inline kronkellijn in de editor. Deze blokkeert het compileren **niet** — de compiler verwijdert types in plaats van ze te controleren |
| Syntaxfout                     | Wanneer je op **Compile** klikt | De editor, voordat het je storefront kan bereiken                                                                                          |
| Een crash tijdens het renderen | Op de storefront, zodra live    | `console.error('[aftersell-cart] module crashed: …')`                                                                                      |

Omdat het blok stilletjes verdwijnt in plaats van zichtbaar een fout te geven, controleer je een template altijd in de [voorvertoning](/nl/aftersell/cart/previewing-carts) voordat je publiceert. Als een blok is verdwenen, open dan eerst de browserconsole.

Twee dingen om op te letten, omdat beide een template laten crashen die anders veronderstelt:

* **Nullable props.** Veel props zijn `null` onder normale omstandigheden (`logoUrl` zonder logo, `imageUrl` zonder afbeelding, `variantTitle` bij een product met één variant). Controleer voordat je ze gebruikt.
* **Arrays die leeg kunnen zijn.** `discountTags` en `discountCodes` zijn vaker wel dan niet `[]`.

<div id="limitations">
  ## Beperkingen
</div>

* **Aangepaste templates zijn weergave-overrides.** Om logica op de cart uit te voeren (abonneren op events, items toevoegen, reageren op wijzigingen), gebruik je [Aangepaste scripts](/nl/aftersell/cart/custom-scripts) en de [Cart SDK](/nl/aftersell/cart/sdk-overview).
* **Bijna elk blok ondersteunt er een.** De uitzonderingen zijn het **[Express payments](/nl/aftersell/cart/express-payments-block)**-blok, dat Shopify's eigen betaalknoppen host, en de **[Cart items](/nl/aftersell/cart/cart-items-block)**-container zelf, hoewel de **Product**-rij erbinnen wél een aangepaste template ondersteunt.
* **Een template kan niet veranderen wat een blok fundamenteel doet.** Het verandert hoe de gegevens van het blok worden gepresenteerd, niet de gegevens of het gedrag erachter.

<div id="props-for-each-block">
  ## Props per blok
</div>

Elk blok geeft zijn eigen gegevens door. De volledige prop-tabel, met types en een uitgewerkt voorbeeld, staat op de pagina van dat blok:

| Blok                                                                                  | Props die het ontvangt                                                                                                             |
| ------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| [Header](/nl/aftersell/cart/header-block#custom-template)                             | `title`, `logoUrl`, `leftSection`, `rightSection`, `itemCount`, `onClose`, `isLoading`                                             |
| [Banner](/nl/aftersell/cart/banner-block#custom-template)                             | `text`, `shouldUseTimer`, `isTimerExpiredAndShouldHide`, `isLoading`                                                               |
| [Rewards](/nl/aftersell/cart/rewards-block#custom-template)                           | `milestones`, `rewardsMessageHtml`, `showIcons`, `isLoading`                                                                       |
| [Cart items · Product](/nl/aftersell/cart/cart-items-block#custom-template)           | 25 props: content per regel, identifiers en aantal-bedieningen                                                                     |
| [Subscription upgrade](/nl/aftersell/cart/subscription-upgrade-block#custom-template) | `view`, `selectPlan`, `onChange`, `oneTimeValue` en meer                                                                           |
| [Summary](/nl/aftersell/cart/summary-block#custom-template)                           | `leftHtml`, `rightHtml`, `discountCodes`, `totalPrice`, `savings` en meer                                                          |
| [Checkout button](/nl/aftersell/cart/checkout-button-block#custom-template)           | `label`, `href`, `isLoading`                                                                                                       |
| [Discount code](/nl/aftersell/cart/discount-code-block#custom-template)               | `discountCodeInput`, `placeholder`, `buttonText`, `isValidating`, `isInvalid`, `setDiscountCodeInput`, `handleSubmit`, `isLoading` |
| [Empty cart](/nl/aftersell/cart/empty-cart-block#custom-template)                     | `text`, `cta`, `href`                                                                                                              |
| [Image](/nl/aftersell/cart/image-block#custom-template)                               | `imageUrl`, `altText`, `maxHeight`, `fullWidth`                                                                                    |
| [Notes](/nl/aftersell/cart/notes-block#custom-template)                               | `titleHtml`, `placeholder`, `noteInput`, `status`, `isExpanded`, `onNoteChange`, `onNoteBlur`, `onToggle` en meer                  |
| [Product add-on](/nl/aftersell/cart/product-add-on-block#custom-template)             | `addonTitleHtml`, `descriptionHtml`, `priceHtml`, `imageUrl`, `format`, `isEnabled`, `handleAdd`, `handleToggle` en meer           |
| [Shipping protection](/nl/aftersell/cart/shipping-protection-block#custom-template)   | `titleHtml`, `descriptionHtml`, `priceHtml`, `imageUrl`, `format`, `isEnabled`, `handleAdd`, `handleToggle` en meer                |
| [Upsells](/nl/aftersell/cart/upsells-block#custom-template)                           | `title`, `addButtonText`, `layout`, `upsells`, `selectVariant`, `handleAdd` en de carrouselbedieningen                             |

Het [Custom code](/nl/aftersell/cart/custom-code-blocks)-blok is het enige vlak dat markup **toevoegt** in plaats van de rendering van een blok te vervangen, dus zijn props zijn anders: de hele cart, plus een add-to-cart-actie. Zie [Custom code-blokken → Props](/nl/aftersell/cart/custom-code-blocks#props).
