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

# Benutzerdefinierte Templates

> Überschreibe das Rendering jedes Aftersell Cart-Blocks mit eigenem JSX: was ein Template ersetzt, was im Scope ist, wie du es stylst und wo du die Props jedes Blocks findest.

Mit einem **benutzerdefinierten Template** kannst du überschreiben, wie ein einzelner Block gerendert wird. Statt der integrierten UI des Blocks rendert der Warenkorb dein eigenes JSX und nutzt dabei dieselben Daten, die der Block normalerweise verwenden würde. Es ist eine übergreifende Fähigkeit statt eines eigenen Blocks: Die meisten Blöcke stellen sie über ihren **Code**-Tab bereit.

Diese Seite behandelt, was für **jeden** Block gilt. Für die Props, die dir ein bestimmter Block übergibt, springe zur [Referenz des jeweiligen Blocks](#props-for-each-block).

<div id="custom-template-vs-custom-code-block">
  ## Benutzerdefiniertes Template vs. Custom-Code-Block
</div>

Die beiden klingen ähnlich, tun aber unterschiedliche Dinge:

* Ein **benutzerdefiniertes Template** *ersetzt das Rendering eines vorhandenen Blocks* durch dein eigenes Markup und übergibt dir die Daten dieses Blocks (den Titel und die Artikelanzahl des Headers, die Summen der Summary und so weiter). Es fügt nichts Neues hinzu; es gestaltet einen Block neu.
* Der **[Custom code](/de/aftersell/cart/custom-code-blocks)**-Block *fügt einen neuen Block* mit beliebigem HTML oder React an einer beliebigen Stelle im Warenkorb hinzu.

Greif zu einem benutzerdefinierten Template, wenn der integrierte Block fast passt, du aber ein anderes Layout oder Markup brauchst. Greif zu einem Custom-Code-Block, wenn du etwas hinzufügen willst, das die integrierten Blöcke nicht abdecken.

<div id="using-a-custom-template">
  ## Ein benutzerdefiniertes Template verwenden
</div>

1. Wähle einen Block im Editor aus und öffne seinen **Code**-Tab.
2. Bearbeite das Standard-Template. Benutzerdefinierte Templates sind **nur JSX** (die Wahl zwischen HTML und JSX gibt es ausschließlich beim Custom-Code-Block).
3. Klicke auf **Compile**. Das Kompilieren entfernt die Typen und transpiliert das JSX, sodass es **Syntax**-Fehler abfängt. Typfehler verhindern das Kompilieren nicht — der Editor markiert sie inline beim Tippen, mit derselben IntelliSense, die die Props des Blocks automatisch vervollständigt.
4. Aktiviere das Template, damit der Warenkorb es anstelle des integrierten Renderings verwendet.
5. **Reset to default** stellt das ursprüngliche Template des Blocks jederzeit wieder her.

<div id="writing-a-template-with-ai">
  ## Ein Template mit KI schreiben
</div>

Der Code-Tab enthält einen **Copy AI prompt**-Button (✦ Zauberstab-Symbol). Ein Klick darauf kopiert ein in sich geschlossenes Briefing in deine Zwischenablage, das du direkt in eine KI-Chat-Sitzung einfügen kannst (Claude, ChatGPT oder ähnliche).

Der Prompt enthält alles, was die KI braucht, um ein gültiges Template für genau diesen Block zu schreiben:

* Die Compile-Regeln (ein einzelner Ausdruck, kein `export default`, keine Imports)
* Die exakten Props, die der Block erhält, passend zu dem, was die IntelliSense des Editors anzeigt
* Die gesperrte Funktionssignatur, die der Editor erzwingt
* Blockspezifische Regeln (Geldformate, welche Handler zu verdrahten sind, Barrierefreiheitsanforderungen)
* Einen Ausfüllbereich, in den du dein aktuelles Template einfügst und die gewünschte Änderung beschreibst

Nach dem Kopieren öffnest du eine KI-Sitzung, fügst den Prompt ein, füllst die beiden Lücken unten aus (dein aktuelles Template und die gewünschte Änderung) und sendest ab. Die KI liefert ein vollständiges Template zurück, das du in den Editor einfügen und kompilieren kannst.

<Tip>
  Füge dein vorhandenes Template in den Ausfüllbereich ein, statt ihn leer zu lassen. Die KI nutzt es als Ausgangspunkt, sodass jede bereits vorgenommene Anpassung übernommen wird, statt durch den Standard ersetzt zu werden.
</Tip>

<Note>
  Der Prompt ist für jeden Block spezifisch. Der **Copy AI prompt**-Button erscheint nur bei Blöcken, die benutzerdefinierte Templates unterstützen.
</Note>

<Tip>
  Das Standard-Template, mit dem du startest, ist eine **funktionierende Kopie des integrierten Markups des Blocks** — du hast also immer eine korrekte, renderbare Referenz zum Anpassen statt einer leeren Seite. Nutze **Reset to default**, wann immer du diese Referenz zurückhaben willst.

  Es ist nicht immer eine byte-genaue Übereinstimmung. Das Standard-Template des Headers rendert auch `logoUrl`, wofür das integrierte Markup keinen Platz hat — das Aktivieren dieses Templates ist also der Weg, wie ein hochgeladenes Header-Bild überhaupt erst erscheint.
</Tip>

<div id="what-your-template-replaces">
  ## Was dein Template ersetzt
</div>

Ein Template ersetzt das Rendering des Blocks **vollständig**. Um dein JSX bleibt kein Wrapper übrig, was Konsequenzen hat, die du kennen solltest, bevor du anfängst, Dinge zu löschen:

| Du verlierst                                | Was das bedeutet                                                                                                                                                                                                          |
| ------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Das Wrapper-Element des Blocks              | Nichts umschließt dein Markup. Jedes Padding, jede Ausrichtung und jedes Layout, das der Block bereitgestellt hat, musst du jetzt selbst liefern.                                                                         |
| **Die Design-Tab-Einstellungen des Blocks** | Design-Einstellungen werden als Inline-Styles auf dem integrierten Wrapper angewendet, und dieser Wrapper ist weg. Farben, Abstände und Radien, die im Design-Tab gesetzt wurden, **gelten für diesen Block nicht mehr**. |
| Integrierte Barrierefreiheits-Vorkehrungen  | `aria-label`s, Fokus-Handling und semantische Elemente existieren nur, wenn dein JSX sie enthält.                                                                                                                         |

<Warning>
  **Der Design-Tab ist die Stelle, an der die meisten stolpern.** Während ein benutzerdefiniertes Template aktiv ist, sind die Felder des Design-Tabs deaktiviert und neben der Überschrift „Design“ erscheint ein Warnsymbol. Fahre mit der Maus über das Symbol, um den Grund zu sehen. Style den Block stattdessen aus deinem Template heraus, entweder [inline oder mit eigenem CSS](#styling-a-custom-template). Die Felder werden wieder aktiviert, sobald du das benutzerdefinierte Template ausschaltest.
</Warning>

Was du behältst: die Position des Blocks im Warenkorb, seinen Sichtbarkeits-Toggle, seine Einstellungen (die weiterhin die Props speisen, die du erhältst), das [Custom CSS](/de/aftersell/cart/custom-css)-Panel des Warenkorbs und **das integrierte Lade-Skeleton**.

Letzteres überrascht viele. Der Block prüft, ob der Warenkorb noch lädt, *bevor* er dein Template erreicht, sodass das integrierte Skeleton während des Ladens gerendert wird und dein Template erst läuft, wenn der Warenkorb bereit ist. Du musst keinen Ladezustand bauen.

<div id="whats-available-inside-a-template">
  ## Was innerhalb eines Templates verfügbar ist
</div>

Dein Template ist eine einzelne Funktionskomponente. Es wird aus **TSX** kompiliert, sodass Typannotationen erlaubt sind und beim Kompilieren entfernt werden. Deshalb sind die Standard-Templates mit ihnen geschrieben:

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

**Die Signaturzeile und die schließende Klammer sind gesperrt** — der Editor lässt dich keine von beiden bearbeiten, und beim Hovern erscheint „Locked — this line can't be edited.“ Du schreibst den Body dazwischen. **Reset to default** ist das Einzige, was sie ersetzen kann.

Was sonst noch wichtig ist:

* **Du bekommst fünf Hooks:** `useState`, `useEffect`, `useMemo`, `useRef` und `useCallback`. Plus `Fragment`, für `<>…</>`.
* **Es gibt keine Imports.** Du kannst nichts `import`ieren, und es gibt kein `React`-Objekt im Scope, also kein `React.useReducer`, kein `React.Children`. Wenn ein Hook nicht in der obigen Liste steht, ist er nicht verfügbar.
* **Props sind schreibgeschützt.** Das Mutieren einer Prop bringt nichts Nützliches. Um den Warenkorb zu ändern, verwende die Handler-Props, die dir der Block gibt (`onClose`, `increment`, `selectPlan` und so weiter), statt direkt in Props zu schreiben.
* **`window` ist erreichbar**, sodass ein Template das [Cart SDK](/de/aftersell/cart/sdk-overview) über `window.aftersell.cart` aufrufen kann, wenn es etwas braucht, das die Props des Blocks nicht abdecken.

<div id="conventions-across-every-block">
  ## Konventionen über alle Blöcke hinweg
</div>

Drei Regeln gelten überall, und sie zu kennen nimmt dir das meiste Rätselraten ab:

* **`*Html`-Props sind vorab bereinigter Rich Text.** Rendere sie mit `dangerouslySetInnerHTML`. Sie haben den Sanitizer des Warenkorbs bereits durchlaufen, und Händler-Tokens wie `{{total_price}}` sind bereits aufgelöst.
* **Preise, die als `string` ankommen, sind bereits** im Geldformat des Shops formatiert. Preise als `number` sind in Cents. Ein Block gibt dir das eine oder das andere, und die Tabelle jedes Blocks sagt dir, welches.
* **`isLoading` ist innerhalb eines Templates immer `false`.** Der Block rendert sein integriertes Skeleton und ruft dein Template erst auf, wenn der Warenkorb geladen ist — die Prop wird also der Vollständigkeit halber übergeben, nicht damit du darauf verzweigst.

<Note>
  Einige Blöcke geben in bestimmten Zuständen gar nichts zurück, sodass dein Template nie mit leeren Daten aufgerufen wird. Das Rewards-Template sieht nie ein leeres `milestones`, und das Subscription-upgrade-Template sieht nie ein null `view`. Die Referenz jedes Blocks vermerkt, wo das gilt, damit du den Leerzustands-Zweig weglassen kannst.
</Note>

<div id="styling-a-custom-template">
  ## Ein benutzerdefiniertes Template stylen
</div>

Das Standard-Template, mit dem du startest, trägt die Klassennamen des Blocks. Wie du deine Anpassungen stylst, hängt davon ab, wie weit du dich von diesem Ausgangspunkt entfernst.

<div id="the-two-class-families">
  ### Die zwei Klassenfamilien
</div>

Jedes Element in einem Standard-Template trägt einen gepaarten Klassennamen, und die beiden haben sehr unterschiedliche Aufgaben:

| Familie           | Was sie tut                                                                                                                          | CSS dagegen schreiben?                                                                                       |
| ----------------- | ------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------ |
| `cart-internal-*` | **Trägt das integrierte Styling des Blocks.** Jede Regel im Stylesheet des Warenkorbs zielt auf diese Familie.                       | Nein. Sie ist die interne Verkabelung des Warenkorbs, und der Custom-CSS-Editor markiert Selektoren dagegen. |
| `cart-external-*` | **Ein Hook ohne eigenes Styling.** Nichts im Stylesheet des Warenkorbs zielt darauf; sie existiert, damit dein CSS sie greifen kann. | Ja. Das ist der unterstützte Weg, einen Block neu zu stylen.                                                 |

`cart-internal-header__title` ist also das, was den Titel wie den integrierten Titel *aussehen* lässt, und `cart-external-header__title` ist der Griff, den du nehmen sollst, wenn du sein Aussehen ändern willst.

<div id="small-changes-keep-both-classnames">
  ### Kleine Änderungen: beide Klassennamen behalten
</div>

Wenn du Elemente umsortierst, umbenennst oder etwas innerhalb der bestehenden Struktur hinzufügst, lass die Klassennamen in Ruhe. Du behältst das integrierte Aussehen gratis und stylst über [Custom CSS](/de/aftersell/cart/custom-css) neu, das auf die `cart-external-*`-Hooks zielt.

<div id="restructuring-drop-both-classnames">
  ### Umstrukturieren: beide Klassennamen entfernen
</div>

Sobald du die DOM-Struktur änderst statt sie nur anzupassen, nimm **beide** Familien aus deinem Markup und verwende stattdessen [deine eigenen Klassennamen](#option-1-your-own-classnames-plus-custom-css). Für jede gibt es einen eigenen Grund.

**Entferne `cart-internal-*`, weil das integrierte CSS für das integrierte DOM geschrieben wurde.** Behältst du diese Klassen auf umstrukturiertem Markup, erbst du Layout-Regeln, die Elemente voraussetzen, die du nicht mehr hast: Flex-Container, die andere Kinder erwarten, Abstände zwischen Elementen, die verschoben wurden, Positionierung relativ zu etwas, das du entfernt hast. Das zeigt sich meist darin, dass dein eigenes CSS „nicht funktioniert“, weil die integrierten Regeln gewinnen.

<Warning>
  **Entferne `cart-external-*`, weil es ein geteilter Name ist, nicht deiner.** Diese Klassennamen bedeuten auf dem integrierten Markup etwas Bestimmtes, und dein Custom CSS wird einmal für den gesamten Warenkorb geschrieben. Wenn ein umstrukturiertes Template sie wiederverwendet, zielt jede Regel, die du schreibst, sowohl auf deine Struktur als auch auf die integrierte.

  Das geht in dem Moment schief, in dem du das benutzerdefinierte Template ausschaltest: Der Block kehrt zu seinem integrierten Markup zurück, und dein CSS zeigt weiterhin darauf und stylt nun ein DOM, für das es nie geschrieben wurde. Ein eigener Präfix hält die beiden sauber getrennt, sodass das Ausschalten eines Templates ein sauberer Rollback ist.
</Warning>

Zwei Wege, das Gebaute zu stylen:

<div id="option-1-your-own-classnames-plus-custom-css">
  #### Option 1: eigene Klassennamen plus Custom CSS
</div>

Am besten für alles, das du pflegen oder wiederverwenden wirst. Gib deinen Klassen einen Präfix, mit dem niemand sonst kollidiert, üblicherweise deinen Shop- oder Markennamen:

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

Wähle dann im Cart-Editor **Cart settings** im linken Panel und öffne rechts den **Custom CSS**-Tab:

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

Ein Präfix ist wichtiger, als er aussieht. Ohne ihn riskiert eine Klasse wie `.header` oder `.title` eine Kollision mit den eigenen Klassen des Warenkorbs, dem Template einer anderen App oder einem zukünftigen Block.

<div id="option-2-inline-styles">
  #### Option 2: Inline-Styles
</div>

Kein Hin und Her mit dem CSS-Panel, und alles lebt an einem Ort:

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

Gut für Layout-Gerüste und Einmal-Anpassungen. Die Grenzen sind die üblichen: kein `:hover` oder andere Pseudoklassen, keine Media Queries und keine Wiederverwendung über Blöcke hinweg. Greif zu Option 1, sobald du eines davon brauchst.

<div id="picking-an-approach">
  ### Einen Ansatz wählen
</div>

| Situation                                              | Mach das                                                                                 |
| ------------------------------------------------------ | ---------------------------------------------------------------------------------------- |
| Gleiche Struktur, andere Formulierung oder Reihenfolge | Beide Klassennamen behalten, per Custom CSS auf `cart-external-*` neu stylen             |
| Neue Struktur, Styling, das du pflegen wirst           | Eigene Klassen mit Präfix, beide Cart-Familien entfernt                                  |
| Neue Struktur, ein paar schnelle Layout-Regeln         | Inline-Styles, beide Cart-Familien entfernt                                              |
| Viel Custom Code über mehrere Blöcke hinweg            | Überall eigene Klassen mit Präfix, damit jedes Template sauber ausgeschaltet werden kann |

<Note>
  Der Warenkorb wird in einem Shadow Root gerendert, sodass das Stylesheet deines Themes nicht hineinreicht. Styles für ein benutzerdefiniertes Template müssen aus dem eigenen **Custom CSS**-Panel des Warenkorbs oder aus Inline-Styles kommen, nicht aus deinem Theme. Siehe [Custom CSS](/de/aftersell/cart/custom-css).
</Note>

<div id="when-a-template-fails">
  ## Wenn ein Template fehlschlägt
</div>

Ein defektes Template macht nie den Warenkorb kaputt. Der Block rendert **nichts**, und alles drumherum funktioniert weiter — das ist sicher, aber leicht zu übersehen: Eine leere Stelle, wo dein Block sein sollte, ist das Symptom.

| Fehler                 | Wann du ihn siehst              | Wo er gemeldet wird                                                                                                             |
| ---------------------- | ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
| Typfehler              | Beim Tippen                     | Eine Inline-Schlangenlinie im Editor. Er blockiert das Kompilieren **nicht** — der Compiler entfernt Typen, statt sie zu prüfen |
| Syntaxfehler           | Wenn du auf **Compile** klickst | Im Editor, bevor er deinen Storefront erreichen kann                                                                            |
| Ein Crash beim Rendern | Im Storefront, sobald live      | `console.error('[aftersell-cart] module crashed: …')`                                                                           |

Da der Block still verschwindet, statt sichtbar zu fehlern, prüfe ein Template immer in der [Vorschau](/de/aftersell/cart/previewing-carts), bevor du veröffentlichst. Wenn ein Block fehlt, öffne zuerst die Browser-Konsole.

Zwei Dinge, gegen die du dich absichern solltest, da beide ein Template crashen, das vom Gegenteil ausgeht:

* **Nullable Props.** Viele Props sind unter normalen Bedingungen `null` (`logoUrl` ohne Logo, `imageUrl` ohne Bild, `variantTitle` bei einem Produkt mit nur einer Variante). Prüfe sie, bevor du sie verwendest.
* **Arrays, die leer sein können.** `discountTags` und `discountCodes` sind weit öfter `[]` als nicht.

<div id="limitations">
  ## Einschränkungen
</div>

* **Benutzerdefinierte Templates sind Anzeige-Overrides.** Um Logik gegen den Warenkorb auszuführen (Events abonnieren, Artikel hinzufügen, auf Änderungen reagieren), verwende [benutzerdefinierte Scripts](/de/aftersell/cart/custom-scripts) und das [Cart SDK](/de/aftersell/cart/sdk-overview).
* **Fast jeder Block unterstützt eines.** Die Ausnahmen sind der **[Express payments](/de/aftersell/cart/express-payments-block)**-Block, der Shopifys eigene Zahlungsbuttons hostet, und der **[Cart items](/de/aftersell/cart/cart-items-block)**-Container selbst — die **Product**-Zeile darin unterstützt allerdings ein benutzerdefiniertes Template.
* **Ein Template kann nicht ändern, was ein Block grundlegend tut.** Es ändert, wie die Daten des Blocks dargestellt werden, nicht die Daten oder das Verhalten dahinter.

<div id="props-for-each-block">
  ## Props für jeden Block
</div>

Jeder Block übergibt seine eigenen Daten. Die vollständige Prop-Tabelle, mit Typen und einem ausgearbeiteten Beispiel, findest du auf der Seite des jeweiligen Blocks:

| Block                                                                                 | Props, die er erhält                                                                                                               |
| ------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| [Header](/de/aftersell/cart/header-block#custom-template)                             | `title`, `logoUrl`, `leftSection`, `rightSection`, `itemCount`, `onClose`, `isLoading`                                             |
| [Banner](/de/aftersell/cart/banner-block#custom-template)                             | `text`, `shouldUseTimer`, `isTimerExpiredAndShouldHide`, `isLoading`                                                               |
| [Rewards](/de/aftersell/cart/rewards-block#custom-template)                           | `milestones`, `rewardsMessageHtml`, `showIcons`, `isLoading`                                                                       |
| [Cart items · Product](/de/aftersell/cart/cart-items-block#custom-template)           | 25 Props: Inhalt pro Zeile, Identifikatoren und Mengensteuerungen                                                                  |
| [Subscription upgrade](/de/aftersell/cart/subscription-upgrade-block#custom-template) | `view`, `selectPlan`, `onChange`, `oneTimeValue` und mehr                                                                          |
| [Summary](/de/aftersell/cart/summary-block#custom-template)                           | `leftHtml`, `rightHtml`, `discountCodes`, `totalPrice`, `savings` und mehr                                                         |
| [Checkout button](/de/aftersell/cart/checkout-button-block#custom-template)           | `label`, `href`, `isLoading`                                                                                                       |
| [Discount code](/de/aftersell/cart/discount-code-block#custom-template)               | `discountCodeInput`, `placeholder`, `buttonText`, `isValidating`, `isInvalid`, `setDiscountCodeInput`, `handleSubmit`, `isLoading` |
| [Empty cart](/de/aftersell/cart/empty-cart-block#custom-template)                     | `text`, `cta`, `href`                                                                                                              |
| [Image](/de/aftersell/cart/image-block#custom-template)                               | `imageUrl`, `altText`, `maxHeight`, `fullWidth`                                                                                    |
| [Notes](/de/aftersell/cart/notes-block#custom-template)                               | `titleHtml`, `placeholder`, `noteInput`, `status`, `isExpanded`, `onNoteChange`, `onNoteBlur`, `onToggle` und mehr                 |
| [Product add-on](/de/aftersell/cart/product-add-on-block#custom-template)             | `addonTitleHtml`, `descriptionHtml`, `priceHtml`, `imageUrl`, `format`, `isEnabled`, `handleAdd`, `handleToggle` und mehr          |
| [Shipping protection](/de/aftersell/cart/shipping-protection-block#custom-template)   | `titleHtml`, `descriptionHtml`, `priceHtml`, `imageUrl`, `format`, `isEnabled`, `handleAdd`, `handleToggle` und mehr               |
| [Upsells](/de/aftersell/cart/upsells-block#custom-template)                           | `title`, `addButtonText`, `layout`, `upsells`, `selectVariant`, `handleAdd` und die Karussell-Steuerungen                          |

Der [Custom code](/de/aftersell/cart/custom-code-blocks)-Block ist die eine Oberfläche, die Markup **hinzufügt**, statt das Rendering eines Blocks zu ersetzen — seine Props sind daher anders: der gesamte Warenkorb plus eine Add-to-cart-Aktion. Siehe [Custom-Code-Blöcke → Props](/de/aftersell/cart/custom-code-blocks#props).
