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

# Tilpassede skabeloner

> Tilsidesæt, hvordan enhver Aftersell Cart-blok renderes, med din egen JSX: hvad en skabelon erstatter, hvad der er i scope, hvordan du styler den, og hvor du finder hver bloks props.

En **tilpasset skabelon** lader dig tilsidesætte, hvordan en individuel blok renderes. I stedet for blokkens indbyggede UI renderer carten din egen JSX, ved brug af de samme data, blokken normalt ville bruge. Det er en tværgående mulighed snarere end en blok i sig selv: de fleste blokke eksponerer den fra deres **Code**-fane.

Denne side dækker det, der gælder for **alle** blokke. For de props, en specifik blok giver dig, spring til [blokkens egen reference](#props-for-each-block).

<div id="custom-template-vs-custom-code-block">
  ## Tilpasset skabelon vs. Custom code-blok
</div>

Disse lyder ens, men gør forskellige ting:

* En **tilpasset skabelon** *erstatter renderingen af en eksisterende blok* med din egen markup og giver dig den bloks egne data (Headerens titel og vareantal, Summarys totaler og så videre). Den tilføjer intet nyt; den restyler én blok.
* **[Custom code](/da/aftersell/cart/custom-code-blocks)**-blokken *tilføjer en ny blok* med vilkårlig HTML eller React hvor som helst i carten.

Gå efter en tilpasset skabelon, når den indbyggede blok er næsten rigtig, men du har brug for et andet layout eller anden markup. Gå efter en Custom code-blok, når du vil tilføje noget, de indbyggede blokke ikke dækker.

<div id="using-a-custom-template">
  ## Brug af en tilpasset skabelon
</div>

1. Vælg en blok i editoren, og åbn dens **Code**-fane.
2. Redigér standardskabelonen. Tilpassede skabeloner er **kun JSX** (valget mellem HTML og JSX er eksklusivt for Custom code-blokken).
3. Klik på **Compile**. Kompilering fjerner typerne og transpilerer JSX'en, så den fanger **syntaks**-fejl. Typefejl stopper ikke en kompilering — editoren markerer dem inline, mens du skriver, med den samme IntelliSense, der autoudfylder blokkens props.
4. Slå skabelonen til, så carten bruger den i stedet for den indbyggede rendering.
5. **Reset to default** gendanner blokkens oprindelige skabelon når som helst.

<div id="writing-a-template-with-ai">
  ## At skrive en skabelon med AI
</div>

Code-fanen indeholder en **Copy AI prompt**-knap (✦ tryllestavsikon). Et klik på den kopierer en selvstændig brief til din udklipsholder, som du kan indsætte direkte i en AI-chatsession (Claude, ChatGPT eller lignende).

Prompten indeholder alt, hvad AI'en skal bruge for at skrive en gyldig skabelon til den specifikke blok:

* Kompileringsreglerne (ét enkelt udtryk, ingen `export default`, ingen imports)
* De præcise props, blokken modtager, matchende det, editorens IntelliSense viser
* Den låste funktionssignatur, editoren håndhæver
* Blokspecifikke regler (pengeformater, hvilke handlers der skal kobles, tilgængelighedskrav)
* En udfyldningssektion, hvor du indsætter din nuværende skabelon og beskriver den ændring, du ønsker

Efter kopiering skal du åbne en AI-session, indsætte prompten, udfylde de to tomme felter i bunden (din nuværende skabelon og den ændring, du ønsker) og sende. AI'en returnerer en komplet skabelon, du kan indsætte tilbage i editoren og kompilere.

<Tip>
  Indsæt din eksisterende skabelon i udfyldningssektionen i stedet for at lade den stå tom. AI'en bruger den som udgangspunkt, så enhver tilpasning, du allerede har lavet, føres videre i stedet for at blive erstattet af standarden.
</Tip>

<Note>
  Prompten er specifik for hver blok. **Copy AI prompt**-knappen vises kun på blokke, der understøtter tilpassede skabeloner.
</Note>

<Tip>
  Standardskabelonen, du starter fra, er en **fungerende kopi af blokkens indbyggede markup**, så du har altid en korrekt, renderende reference at ændre i stedet for en blank side. Brug **Reset to default**, når du vil have den reference tilbage.

  Det er ikke altid et byte-for-byte-match. Headerens standardskabelon renderer også `logoUrl`, som den indbyggede markup ikke har nogen placering til, så at slå den skabelon til er måden, et uploadet header-billede først vises på.
</Tip>

<div id="what-your-template-replaces">
  ## Hvad din skabelon erstatter
</div>

En skabelon erstatter blokkens rendering **fuldstændigt**. Der er ingen wrapper tilbage omkring din JSX, hvilket har konsekvenser, der er værd at kende, før du begynder at slette ting:

| Du mister                              | Hvad det betyder                                                                                                                                                                         |
| -------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Blokkens wrapper-element               | Intet omslutter din markup. Al padding, justering eller layout, blokken leverede, er nu dit ansvar.                                                                                      |
| **Blokkens Design-fane-indstillinger** | Designindstillinger anvendes som inline-stile på den indbyggede wrapper, og den wrapper er væk. Farver, afstande og radier sat i Design-fanen **holder op med at gælde** for denne blok. |
| Indbyggede tilgængelighedshjælpemidler | `aria-label`s, fokushåndtering og semantiske elementer findes kun, hvis din JSX indeholder dem.                                                                                          |

<Warning>
  **Design-fanen er den, folk bliver fanget af.** Mens en tilpasset skabelon er aktiv, er Design-fanens felter deaktiveret, og et advarselsikon vises ved siden af "Design"-overskriften. Hold musen over ikonet for at se hvorfor. Stil i stedet blokken fra din skabelon, enten [inline eller med din egen CSS](#styling-a-custom-template). Felterne genaktiveres, så snart du slår den tilpassede skabelon fra.
</Warning>

Hvad du beholder: blokkens position i carten, dens synligheds-knap, dens indstillinger (som stadig føder de props, du modtager), cartens [Tilpasset CSS](/da/aftersell/cart/custom-css)-panel og **den indbyggede indlæsnings-skeleton**.

Det sidste overrasker folk. Blokken tjekker, om carten stadig indlæses, *før* den når din skabelon, så den indbyggede skeleton renderes under indlæsning, og din skabelon kører først, når carten er klar. Du behøver ikke bygge en indlæsningstilstand.

<div id="whats-available-inside-a-template">
  ## Hvad der er tilgængeligt inde i en skabelon
</div>

Din skabelon er en enkelt funktionskomponent. Den kompileres fra **TSX**, så typeannotationer er tilladt og fjernes ved kompilering. Det er derfor, standardskabelonerne er skrevet med dem:

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

**Signaturlinjen og den afsluttende klamme er låst** — editoren lader dig ikke redigere nogen af dem, og hold musen over viser "Locked — this line can't be edited." Du skriver kroppen mellem dem. **Reset to default** er det eneste, der kan erstatte dem.

Hvad der ellers er vigtigt:

* **Du får fem hooks:** `useState`, `useEffect`, `useMemo`, `useRef` og `useCallback`. Plus `Fragment`, til `<>…</>`.
* **Der er ingen imports.** Du kan ikke `import`e noget, og der er intet `React`-objekt i scope, så ingen `React.useReducer`, ingen `React.Children`. Hvis en hook ikke er på listen ovenfor, er den ikke tilgængelig.
* **Props er skrivebeskyttede.** At mutere en prop gør ikke noget nyttigt. For at ændre carten skal du bruge de handler-props, blokken giver dig (`onClose`, `increment`, `selectPlan` og så videre) i stedet for at skrive direkte til props.
* **`window` kan nås**, så en skabelon kan kalde [Cart SDK](/da/aftersell/cart/sdk-overview) via `window.aftersell.cart`, når den har brug for noget, blokkens props ikke dækker.

<div id="conventions-across-every-block">
  ## Konventioner på tværs af alle blokke
</div>

Tre regler gælder overalt, og at kende dem fjerner det meste af gætteriet:

* **`*Html`-props er præ-saneret rich text.** Render dem med `dangerouslySetInnerHTML`. De har allerede været gennem cartens sanitizer, og forhandler-tokens som `{{total_price}}` er allerede udfyldt.
* **Priser, der ankommer som `string`, er allerede formateret** i butikkens pengeformat. Priser som `number` er i cent. En blok giver dig det ene eller det andet, og hver bloks tabel angiver hvilket.
* **`isLoading` er altid `false` inde i en skabelon.** Blokken renderer sin indbyggede skeleton og kalder først din skabelon, når carten er indlæst, så proppen videregives for fuldstændighedens skyld snarere end for, at du skal forgrene på den.

<Note>
  Nogle få blokke returnerer slet intet i visse tilstande, så din skabelon kaldes aldrig med tomme data. Rewards-skabelonen ser aldrig en tom `milestones`, og Subscription upgrade-skabelonen ser aldrig et null-`view`. Hver bloks reference angiver, hvor dette gælder, så du kan springe tom-tilstands-forgreningen over.
</Note>

<div id="styling-a-custom-template">
  ## Styling af en tilpasset skabelon
</div>

Standardskabelonen, du starter fra, bærer blokkens klassenavne. Hvordan du styler dine ændringer afhænger af, hvor langt du bevæger dig fra det udgangspunkt.

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

Hvert element i en standardskabelon bærer et parret klassenavn, og de har meget forskellige opgaver:

| Familie           | Hvad den gør                                                                                                    | Skrive CSS mod den?                                                                     |
| ----------------- | --------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------- |
| `cart-internal-*` | **Bærer blokkens indbyggede styling.** Hver regel i cartens stylesheet rammer denne familie.                    | Nej. Det er cartens eget maskineri, og Custom CSS-editoren markerer selektorer mod den. |
| `cart-external-*` | **En krog uden egen styling.** Intet i cartens stylesheet rammer den; den findes, for at din CSS kan gribe fat. | Ja. Dette er den understøttede måde at restyle en blok på.                              |

Så `cart-internal-header__title` er det, der får titlen til at *ligne* den indbyggede titel, og `cart-external-header__title` er håndtaget, du skal gribe, når du vil ændre, hvordan den ser ud.

<div id="small-changes-keep-both-classnames">
  ### Små ændringer: behold begge klassenavne
</div>

Hvis du omarrangerer elementer, omdøber eller tilføjer noget inde i den eksisterende struktur, skal du lade klassenavnene være. Du beholder det indbyggede udseende gratis, og du restyler gennem [Tilpasset CSS](/da/aftersell/cart/custom-css) rettet mod `cart-external-*`-krogene.

<div id="restructuring-drop-both-classnames">
  ### Omstrukturering: drop begge klassenavne
</div>

Når du ændrer DOM-strukturen frem for at justere den, skal du fjerne **begge** familier fra din markup og i stedet bruge [dine egne klassenavne](#option-1-your-own-classnames-plus-custom-css). Der er en separat grund til hver.

**Drop `cart-internal-*`, fordi den indbyggede CSS blev skrevet til den indbyggede DOM.** Behold de klasser på omstruktureret markup, og du arver layoutregler, der forudsætter elementer, du ikke længere har: flex-containere, der forventer andre børn, afstande mellem elementer, der er flyttet, positionering i forhold til noget, du har fjernet. Dette viser sig som regel ved, at din egen CSS "ikke virker", når det er de indbyggede regler, der vinder.

<Warning>
  **Drop `cart-external-*`, fordi det er et delt navn, ikke dit.** De klassenavne betyder noget specifikt på den indbyggede markup, og din Custom CSS skrives én gang for hele carten. Hvis en omstruktureret skabelon genbruger dem, rammer enhver regel, du skriver, både din struktur og den indbyggede.

  Det går galt i det øjeblik, du slår den tilpassede skabelon fra: blokken vender tilbage til sin indbyggede markup, og din CSS peger stadig på den og styler nu en DOM, den aldrig blev skrevet til. Dit eget præfiks holder de to rent adskilt, så at slå en skabelon fra er en ren tilbagevenden.
</Warning>

To måder at style det, du har bygget:

<div id="option-1-your-own-classnames-plus-custom-css">
  #### Mulighed 1: dine egne klassenavne plus Custom CSS
</div>

Bedst til alt, hvad du vil vedligeholde eller genbruge. Giv dine klasser et præfiks, ingen andre kolliderer med, som regel dit butiks- eller brandnavn:

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

Derefter skal du i cart-editoren vælge **Cart settings** i venstre panel og åbne **Custom CSS**-fanen til højre:

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

Et præfiks betyder mere, end det ser ud til. Uden et risikerer en klasse som `.header` eller `.title` at kollidere med cartens egne klasser, en anden apps skabelon eller en fremtidig blok.

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

Ingen tur rundt om CSS-panelet, og alt bor ét sted:

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

Godt til layout-stillads og engangsting. Dens grænser er de sædvanlige: ingen `:hover` eller andre pseudoklasser, ingen media queries og ingen genbrug på tværs af blokke. Gå til Mulighed 1, når du vil have noget af det.

<div id="picking-an-approach">
  ### Valg af tilgang
</div>

| Situation                                     | Gør dette                                                                  |
| --------------------------------------------- | -------------------------------------------------------------------------- |
| Samme struktur, anden ordlyd eller rækkefølge | Behold begge klassenavne, restyl via Custom CSS på `cart-external-*`       |
| Ny struktur, styling du vil vedligeholde      | Dine egne præfiksede klasser, begge cart-familier droppet                  |
| Ny struktur, et par hurtige layoutregler      | Inline-stile, begge cart-familier droppet                                  |
| Meget tilpasset kode på tværs af flere blokke | Dine egne præfiksede klasser overalt, så enhver skabelon kan slås fra rent |

<Note>
  Carten renderes i en shadow root, så dit temas stylesheet kan ikke nå ind i den. Stile til en tilpasset skabelon skal komme fra cartens eget **Custom CSS**-panel eller fra inline-stile, ikke fra dit tema. Se [Tilpasset CSS](/da/aftersell/cart/custom-css).
</Note>

<div id="when-a-template-fails">
  ## Når en skabelon fejler
</div>

En ødelagt skabelon ødelægger aldrig carten. Blokken renderer **intet**, og alt omkring den fungerer fortsat, hvilket er sikkert, men let at overse: et tomt rum, hvor din blok skulle være, er symptomet.

| Fejl                       | Hvornår du ser den               | Hvor den rapporteres                                                                                                     |
| -------------------------- | -------------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
| Typefejl                   | Mens du skriver                  | En inline-bølgestreg i editoren. Den blokerer **ikke** kompilering — kompileren fjerner typer i stedet for at tjekke dem |
| Syntaksfejl                | Når du klikker på **Compile**    | Editoren, før den kan nå din storefront                                                                                  |
| Et nedbrud under rendering | På storefronten, når den er live | `console.error('[aftersell-cart] module crashed: …')`                                                                    |

Fordi blokken forsvinder i stilhed i stedet for at fejle synligt, bør du altid tjekke en skabelon i [forhåndsvisning](/da/aftersell/cart/previewing-carts), før du publicerer. Hvis en blok er forsvundet, skal du først åbne browserkonsollen.

To ting, der er værd at gardere sig mod, da begge crasher en skabelon, der antager andet:

* **Props, der kan være null.** Mange props er `null` under normale forhold (`logoUrl` uden logo, `imageUrl` uden billede, `variantTitle` på et produkt med én variant). Tjek, før du bruger dem.
* **Arrays, der kan være tomme.** `discountTags` og `discountCodes` er langt oftere `[]` end ej.

<div id="limitations">
  ## Begrænsninger
</div>

* **Tilpassede skabeloner er visningstilsidesættelser.** For at køre logik mod carten (abonnere på events, tilføje varer, reagere på ændringer) skal du bruge [Tilpassede scripts](/da/aftersell/cart/custom-scripts) og [Cart SDK](/da/aftersell/cart/sdk-overview).
* **Næsten alle blokke understøtter en.** Undtagelserne er **[Express payments](/da/aftersell/cart/express-payments-block)**-blokken, som rummer Shopifys egne betalingsknapper, og selve **[Cart items](/da/aftersell/cart/cart-items-block)**-containeren, selvom **Product**-rækken inde i den understøtter en tilpasset skabelon.
* **En skabelon kan ikke ændre, hvad en blok grundlæggende gør.** Den ændrer, hvordan blokkens data præsenteres, ikke dataene eller adfærden bag dem.

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

Hver blok videregiver sine egne data. Den fulde prop-tabel, med typer og et gennemarbejdet eksempel, ligger på den bloks side:

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

[Custom code](/da/aftersell/cart/custom-code-blocks)-blokken er den ene flade, der **tilføjer** markup i stedet for at erstatte en bloks rendering, så dens props er anderledes: hele carten, plus en læg-i-kurv-handling. Se [Custom code-blokke → Props](/da/aftersell/cart/custom-code-blocks#props).
