> For AI agents: the complete documentation index is available at https://nhanbe.id.vn/llms.txt, the full documentation bundle is available at https://nhanbe.id.vn/llms-full.txt.

# Experience Fragments

## 16 – Experience Fragments

> **Target:** 3–4 years experienced AEM Developer **Syllabus point covered (24, completing it):** _"CF and XF, and the difference between them."_ **Project domain:** a global energy technology company's marketing site.

***

## Before we start — this file exists to complete one comparison

File 15 covered Content Fragments. This one covers Experience Fragments, and more importantly it gives you the **full comparison**, because your syllabus asks for the difference and that is what actually gets asked.

The sentence to build everything on, repeated from file 15 because it's the answer:

> **A Content Fragment is content without presentation. An Experience Fragment is presentation with content.**

**And here's the framing that makes the distinction land**, which most candidates miss: they reuse along **different axes**.

- A **Content Fragment** is reused across **channels** — the same product specification on the website, in the mobile app, in a partner's system.
- An **Experience Fragment** is reused across **pages** — the same promo banner on twenty product pages.

One is about _where the content goes_. The other is about _where the experience appears_. Say it that way and the interviewer knows you understand rather than recite.

***

## 1. Introduction

### 1.1 What an Experience Fragment is

> **An Experience Fragment is a group of components, laid out and styled, saved so it can be reused on many pages.**

Concretely: your site header. It's a logo component, a navigation component, a search component and a language selector, arranged in a particular way with particular styling. Every page needs it, and it must be identical everywhere.

**Without Experience Fragments**, you'd either build it into the page template's structure — which works but means a change requires a developer — or authors would rebuild it per page, which is unmaintainable.

**With one**, it's authored once as a normal page in the page editor, and referenced wherever it's needed. Change it, and every page using it changes.

### 1.2 The key structural fact

**An Experience Fragment is essentially a page.**

It lives under `/content/experience-fragments`, it's a `cq:Page`, it's built from a **template**, and it's edited in the **page editor** with drag and drop. Everything you know about pages applies — components, policies, templates, publishing, MSM.

**Contrast that with a Content Fragment**, which is a `dam:Asset` in the DAM, built from a **Content Fragment Model**, and edited in a form-like editor.

**That single structural difference explains almost all the others:**

| Because a CF is an asset from a model… | Because an XF is a page from a template… |
| -------------------------------------- | ---------------------------------------- |
| It has typed fields                    | It has components                        |
| It has no layout                       | It has full layout and styling           |
| It's edited as a form                  | It's edited in the page editor           |
| It delivers as JSON                    | It delivers as HTML                      |
| It's for channels                      | It's for pages                           |

**If you can derive the differences from "one is an asset, one is a page," you don't need to memorise the comparison table.**

### 1.3 A real project example to adapt

> "We use Experience Fragments for the header, the footer, and reusable promotional blocks. The header and footer are placed in the page template's structure, so they're on every page and authors can't remove them — but they're authored as Experience Fragments, so the content team can change the navigation without a deployment.
>
> The useful part for us is localisation. We have twenty country sites, and the Core Components Experience Fragment component can resolve a localised fragment based on the current page's language — so one component in one template structure serves every country, each getting its own header content.
>
> We also use the plain HTML export for a couple of promotional blocks that a partner embeds on their own site, which means they always get our current version rather than a copy that drifts."

That covers the header/footer pattern, template structure placement, localisation, and the plain HTML export — four things that show real use rather than theory.

***

## 2. Core Concepts

### 2.1 Where they live, and the structure

```text
/content/experience-fragments/
└── energy/
    └── de/
        └── de/
            └── site/
                └── header                 ← the Experience Fragment
                    ├── master             ← a VARIATION (a cq:Page)
                    │   └── jcr:content
                    │       └── root/      ← the actual components
                    └── social             ← another variation
```

**Two levels to notice:**

**The Experience Fragment itself** is a container. **Variations** live inside it, and each variation is a page with its own component tree.

**`master` is the default variation.** You reference a specific variation, not the fragment as a whole — so a reference points at `.../header/master`.

**And the folder structure carries locale**, which is what makes localisation work — section 2.4.

### 2.2 Variations — and how they differ from CF variations

**This is a good comparison question**, because both CF and XF have "variations" and they mean different things.

|                              | Content Fragment variation         | Experience Fragment variation |
| ---------------------------- | ---------------------------------- | ----------------------------- |
| What varies                  | The **wording**                    | The **layout and components** |
| Example                      | A shorter description for social   | A Facebook-formatted version  |
| Stored as                    | A sibling under `jcr:content/data` | **A separate page**           |
| Can use a different template | No                                 | **Yes**                       |

**An XF variation can use a different template entirely**, which is the point — a Facebook variation has different dimensions, different constraints, and genuinely different components from the web variation.

AEM ships templates for social variations. In practice most projects use the web variation and occasionally one more.

### 2.3 The three ways an Experience Fragment is used

**1. Placed on a page by an author.** The Experience Fragment component, pointed at a variation. This is the promotional-banner case — an author drops it on twenty pages, and changing the fragment changes all twenty.

**2. Placed in a template's structure.** This is the header and footer case, and it's the more architecturally interesting one.

From file 03: components in a template's **structure** appear on every page using that template and are **locked** so authors can't remove them. Put an Experience Fragment component there, and you get:

- The header appears on every page — guaranteed by the template structure.
- Authors can't delete it — it's locked structure.
- But the header's **content** is authored in the page editor as an Experience Fragment, so the content team changes navigation without a deployment.

**That combination is genuinely useful**, and being able to explain why it's better than hardcoding the header in the template is a good answer: the template guarantees presence, the fragment allows change.

**3. Exported as plain HTML.** `.plain.html` renders just the fragment's markup, with no page chrome. Used by external systems, email templates, and Adobe Target.

### 2.4 Localised Experience Fragments — the header/footer pattern

**This is the pattern worth understanding**, because it connects to file 12 and it's how multi-country sites actually work.

**The problem.** Twenty country sites all need a header. Structurally identical — logo, navigation, search, language selector. But the content differs: navigation labels are translated, the language selector shows different options, some countries have extra links.

**The naive approaches both fail.** One shared header means no localisation. Twenty separate references in twenty templates means twenty templates to maintain.

**The solution.** The Core Components Experience Fragment component supports **localisation**. You place one component in one template structure, and it resolves the correct localised fragment based on the current page's language.

```text
Page:      /content/energy/de/de/products/transformers
                            ↑ locale

Resolves:  /content/experience-fragments/energy/de/de/site/header/master
                                                 ↑ same locale
```

**One component, one template, twenty localised headers.** The structure carries the locale, and the component does the lookup.

**And it composes with MSM (file 12).** Experience Fragments are pages, so they can be live copies. A country's header can be a live copy of a language master's header — inheriting structure while allowing local exceptions, exactly like site content.

**The interview answer:**

> "The pattern we use is placing an Experience Fragment component in the page template's **structure** for the header and footer. That gives us two things at once: the template guarantees it's on every page and authors can't remove it, but the content is authored as a fragment in the page editor, so the content team changes navigation without a deployment.
>
> For twenty country sites, the Core Components Experience Fragment component supports **localisation** — it resolves the fragment matching the current page's locale from the folder structure. So one component in one template serves every country, each getting its own header.
>
> And because Experience Fragments are pages, they work with MSM — a country header can be a live copy of a language master's header, inheriting structure with local exceptions."

### 2.5 Plain HTML export

`.plain.html` on an Experience Fragment variation renders **just the fragment's markup** — no page wrapper, no head, no site chrome.

```text
/content/experience-fragments/energy/de/de/site/promo/master.plain.html
```

**What it's for:**

**Third-party embedding.** A partner site includes your promotional block. They get your current version rather than a copy that drifts out of date.

**Email templates.** Marketing tools that need HTML.

**Adobe Target.** Experience Fragments can be exported to Target as offers, for personalisation and testing.

**The caching point worth making:** it's a normal GET on a path-based URL, so the dispatcher and CDN cache it like any page. Which is good — but it also means a third party may serve a cached version, so invalidation matters when the fragment changes.

**And the security point:** if you're exposing it to a third party, that URL is public. It should contain nothing that isn't meant to be.

### 2.6 Can an Experience Fragment contain a Content Fragment?

**Yes** — and this question is a good test of whether you understand the relationship.

An Experience Fragment is a group of components. One of those components can be a Content Fragment component, rendering a fragment.

**A concrete case:** a product promo Experience Fragment — heading, image, call-to-action, laid out and styled — where the specification block inside it is rendered from a Content Fragment. The _layout_ is reused across pages; the _specification data_ is reused across channels.

**They're not alternatives. They're different axes**, and a real page often uses both.

### 2.7 The full comparison (syllabus point 24)

**This is the table the question is asking for.**

|                        | **Content Fragment**                                      | **Experience Fragment**                           |
| ---------------------- | --------------------------------------------------------- | ------------------------------------------------- |
| **In one line**        | Content **without** presentation                          | Presentation **with** content                     |
| Contains               | Typed fields — text, number, date, references             | **Actual components**, laid out and styled        |
| Node type              | **`dam:Asset`**                                           | **`cq:Page`**                                     |
| Stored at              | `/content/dam/...`                                        | `/content/experience-fragments/...`               |
| Created from           | A **Content Fragment Model** (`/conf/.../dam/cfm/models`) | A **template** (`/conf/.../wcm/templates`)        |
| Edited in              | The Content Fragment editor — **form-like**               | The **page editor** — drag and drop               |
| Variations vary        | The **wording**                                           | The **layout**, and can use a different template  |
| Delivered as           | **JSON** via GraphQL, or rendered by a component          | **HTML**, or plain HTML export                    |
| Headless               | **Yes — the headless building block**                     | Partially — plain HTML only                       |
| Reused across          | **Channels** — web, app, partner                          | **Pages**                                         |
| Translation            | Translated as content                                     | Translated as **pages** — MSM and language copies |
| Typical use            | Product specifications, articles, structured data         | **Header, footer, promo banner, campaign block**  |
| Can contain the other? | No                                                        | **Yes** — an XF can include a CF component        |

**The derivation to remember**, because it beats memorising the table:

> **A Content Fragment is an asset built from a model. An Experience Fragment is a page built from a template.** Everything else follows.

### 2.8 Choosing between them

**Use a Content Fragment when:**

- The content is consumed by more than one **channel**
- It's structured — distinct typed fields
- It has its own lifecycle, independent of any page
- A mobile app or external system needs it as data

**Use an Experience Fragment when:**

- You're reusing a **laid-out piece of a page** across pages
- The presentation is part of what's being reused
- It's a header, footer, banner or campaign block
- A third party needs the rendered HTML

**A useful test question:** _"If I gave this to a mobile app developer, would they want the data or the HTML?"_ Data means Content Fragment. HTML means Experience Fragment.

***

## 3. Internal Working

### 3.1 How an Experience Fragment renders into a page

graph TD A\["Page requested"] --> B\["Page renders its components"] B --> C\["Experience Fragment component"] C --> D\{"Localised, or a\<br/>fixed path?"} D -->|"Localised"| E\["Resolve the fragment\<br/>matching the page's locale"] D -->|"Fixed"| F\["Use the configured path"] E --> G\["Include the variation's\<br/>component tree"] F --> G G --> H\["Rendered inline —\<br/>part of THIS page's HTML"]

**The key consequence is at the bottom:** the fragment is rendered **inline** into the page. It becomes part of that page's HTML, and therefore part of that page's dispatcher cache entry.

**Which produces the invalidation problem in the next section.**

### 3.2 The invalidation problem

**This is the practical issue with Experience Fragments**, and it's the same shape as the derived listing in file 02 and cached GraphQL responses in file 15.

graph TD A\["Author changes the header\<br/>Experience Fragment"] --> B\["Publish the fragment"] B --> C\["The fragment is updated on publish ✓"] C --> D\{"What about the 5,000 pages\<br/>that RENDER it?"} D --> E\["Their CACHED HTML still contains\<br/>the OLD header"] E --> F\["Every page needs invalidating"]

**The header is rendered into every page's cached HTML.** So publishing the fragment updates the fragment, and every cached page keeps serving the old version until it's invalidated.

**For a header or footer that means flushing essentially the whole site.** Which is correct, and also a significant operation on a large site — a full cache flush means a burst of cache misses while everything re-renders.

**Three things follow, and saying them shows operational awareness:**

**Header and footer changes are not casual.** They invalidate everything.

**They should be done at a sensible time**, not during peak traffic, because the re-render burst hits publish.

**And you need the flush rule to exist.** Publishing a fragment doesn't automatically invalidate the pages that include it — something has to make that connection.

### 3.3 Why an Experience Fragment looks wrong in its own editor

A practical problem worth knowing, because the cause isn't obvious.

**The symptom:** the header looks correct on a page and completely unstyled when you open the Experience Fragment itself for editing.

**The cause:** the Experience Fragment is rendered by **its own template**, and that template's page policy decides which **clientlibs** load (files 03 and 04). If the XF template doesn't include the site's clientlibs, the fragment renders without the site's CSS.

**The fix** is aligning the XF template's page policy with the site's, so the fragment previews accurately.

**Why it matters beyond aesthetics:** authors editing a fragment that doesn't look like the real thing make layout decisions blind. It's a genuine authoring-experience problem, not a cosmetic one.

***

## 8. Configuration Examples

### 8.1 An Experience Fragment component in a template structure

Inside a page template's `structure`, from file 03:

```xml
<root
    jcr:primaryType="nt:unstructured"
    sling:resourceType="wcm/foundation/components/responsivegrid">

    <!-- LOCKED structure component: guaranteed on every page using this
         template, and authors cannot delete it. But the CONTENT is an
         Experience Fragment, so the content team changes navigation
         without a deployment.

         Note: no editable="{Boolean}true" -- deliberately locked. -->
    <header
        jcr:primaryType="nt:unstructured"
        sling:resourceType="energy/components/experiencefragment"
        fragmentVariationPath="/content/experience-fragments/energy/site/header/master"/>

    <container
        jcr:primaryType="nt:unstructured"
        sling:resourceType="wcm/foundation/components/responsivegrid"/>

    <footer
        jcr:primaryType="nt:unstructured"
        sling:resourceType="energy/components/experiencefragment"
        fragmentVariationPath="/content/experience-fragments/energy/site/footer/master"/>

</root>
```

**The `fragmentVariationPath` points at a variation**, not the fragment itself — `.../header/master`, not `.../header`.

**And for a localised site**, the Core Components component resolves the locale-specific fragment from the page's language rather than using a fixed path — so one template serves every country.

### 8.2 The proxy component

Following the file 02 pattern:

`/apps/energy/components/experiencefragment/.content.xml`

```xml
<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0"
          xmlns:cq="http://www.day.com/jcr/cq/1.0"
          xmlns:jcr="http://www.jcp.org/jcr/1.0"
    jcr:primaryType="cq:Component"
    jcr:title="Experience Fragment"
    componentGroup="Energy - Structure"

    <!-- Proxy the Core Component: we control the version, and we can
         override the HTL later without touching content. Same reasoning
         as file 02. -->
    sling:resourceSuperType="core/wcm/components/experiencefragment/v1/experiencefragment"/>
```

### 8.3 The folder structure for localisation

```text
/content/experience-fragments/energy/
├── language-masters/
│   ├── en/site/header/master        ← authored
│   └── de/site/header/master        ← language copy of en
├── de/de/site/header/master         ← LIVE COPY of language-masters/de
├── ch/de/site/header/master         ← LIVE COPY of language-masters/de
└── us/en/site/header/master         ← LIVE COPY of language-masters/en
```

**This mirrors the content structure from file 12 exactly**, and that's the point: Experience Fragments are pages, so the same MSM patterns apply. Translate horizontally in the language masters, distribute vertically to the country fragments.

### 8.4 Plain HTML export

```text
GET /content/experience-fragments/energy/de/de/site/promo/master.plain.html
```

Returns just the fragment's markup:

```html
<div class="cmp-promo">
    <h2 class="cmp-promo__title">Neue Transformatorenreihe</h2>
    <p class="cmp-promo__text">...</p>
    <a class="cmp-cta cmp-cta--arrow" href="/de/de/products/transformers">Mehr erfahren</a>
</div>
```

**Three things to note:**

**No page chrome** — no `<html>`, no `<head>`, no site header.

**It's a normal path-based GET**, so the dispatcher and CDN cache it like a page. Good for load; means invalidation matters.

**The class names are ours.** A consumer either includes our clientlib or writes their own styles. If they want it in _their_ design system, they wanted a Content Fragment — story 3.

***

## 9. Common Mistakes

| The mistake                                                | What happens                                 | The fix                                                     |
| ---------------------------------------------------------- | -------------------------------------------- | ----------------------------------------------------------- |
| Not publishing the fragment                                | Works on author, missing on publish          | XFs have their own publication state                        |
| Not planning invalidation                                  | Pages keep serving the old fragment          | A flush rule connecting fragment publish to including pages |
| Changing a header during peak hours                        | Near-full cache flush and a re-render burst  | Schedule it                                                 |
| XF template missing the site's clientlibs                  | **Authors edit against an unstyled preview** | Align the XF template's page policy                         |
| Referencing the fragment rather than a variation           | Doesn't resolve                              | Point at `.../master`                                       |
| Using an XF where a CF is right                            | A consumer gets HTML it can't structure      | **Ask: data or HTML?**                                      |
| Using an XF for a single-use block                         | Indirection and a publish step for no reuse  | A component on the page                                     |
| Hardcoding the header in the template                      | Content changes need a developer             | XF in the template structure                                |
| Placing the header as initial content instead of structure | Authors can delete it                        | Structure, locked (file 03)                                 |
| Twenty templates for twenty countries                      | Unmaintainable                               | **One localised XF component**                              |
| Exposing internal content in a plain HTML export           | It's a **public URL**                        | Review what's in the fragment                               |
| Assuming a partner wants the HTML                          | They may want the data                       | Ask before building                                         |
| Inheritance cancelled at page level on a country header    | Silently stops receiving all changes         | File 12's discipline applies                                |

***

## 10. Best Practices

**On placement.** Header and footer belong in the **template structure**, locked — guaranteed present, undeletable, but content-authorable.

**On localisation.** One localised Experience Fragment component rather than one template per country. And use MSM for the fragments themselves, since they're pages.

**On invalidation.** Plan it before you ship. A header change invalidates everything, so schedule those changes and make sure a flush rule exists connecting fragment publication to including pages.

**On previewing.** Align the XF template's page policy with the site's, so authors edit against an accurate rendering. This is not cosmetic — they make layout decisions against what they see.

**On choosing.** Ask whether a consumer wants the data or the HTML. Data is a Content Fragment; HTML is an Experience Fragment. And remember they compose — an XF can contain a CF.

**On the plain HTML export.** Remember it's a public URL, and agree the styling question with the consumer before shipping rather than after.

***

## 11. Debugging Tips

**"The fragment doesn't appear on publish."** The fragment wasn't published — it has its own publication state, exactly like a Content Fragment. Publishing pages that include it doesn't publish it.

**"I changed the fragment and pages show the old version."** It's rendered inline, so it's part of every including page's cached HTML. The fragment is updated; the pages are cached. Check whether the flush actually reached those pages.

**"The fragment looks unstyled in its own editor."** The XF template's page policy doesn't include the site's clientlibs (files 03 and 04).

**"The localised fragment isn't resolving."** The folder structure under `/content/experience-fragments` has to mirror the locale structure the component expects. A mismatch means it falls back or finds nothing.

**"I can't find what uses this fragment."** The **References panel** — the same tool as for Content Fragments. A fragment doesn't know where it's used, which is the point, so the tooling has to tell you.

| Tool                               | Answers                                     |
| ---------------------------------- | ------------------------------------------- |
| The References panel               | Which pages include this fragment           |
| Fragment publication status        | Has it been activated                       |
| The XF template's page policy      | Which clientlibs load in the editor         |
| Page source on publish             | Is the old or new fragment markup cached    |
| Private window on publish directly | Anonymous behaviour, without the dispatcher |

***

## 12. Performance Notes

**The fragment renders inline**, so it's an include during page render — a small cost, and it becomes part of the page's cache entry.

**The real cost is invalidation.** A header change invalidates every page. On a large site that's a near-full flush plus a re-render burst on publish, which is a genuine operational event rather than a background one.

**Mitigations:** schedule those changes outside peak hours, and use the dispatcher's grace period so stale content is served briefly during a flush rather than every request stampeding publish at once.

**Many fragments on one page** each add an include. That's rarely the bottleneck, but a page assembled from a dozen fragments is doing a dozen includes.

**The plain HTML export caches normally**, which is good for third-party load — and means the same invalidation thinking applies.

***

## 14. Comparison Tables

**The full CF vs XF comparison** — section 2.7. Learn the **derivation** rather than the table:

> **A Content Fragment is an asset built from a model. An Experience Fragment is a page built from a template.**

**Variations, compared**

|                    | CF variation                       | XF variation              |
| ------------------ | ---------------------------------- | ------------------------- |
| Varies             | **Wording**                        | **Layout and components** |
| Stored as          | A sibling under `jcr:content/data` | **A separate page**       |
| Different template | No                                 | **Yes**                   |
| Example            | A shorter description              | A Facebook version        |

**How each is delivered**

|                    | CF                      | XF                |
| ------------------ | ----------------------- | ----------------- |
| Rendered on a page | By a component          | Inline include    |
| To an app          | **JSON via GraphQL**    | Not really        |
| To a third party   | GraphQL persisted query | **`.plain.html`** |
| To Adobe Target    | —                       | **As an offer**   |

**Placement options for an XF**

| Where                         | Effect                                               |
| ----------------------------- | ---------------------------------------------------- |
| Author places it on a page    | Reusable block, author-controlled                    |
| **In the template structure** | **Guaranteed present, locked** — headers and footers |
| Plain HTML export             | External consumption                                 |

***

## Next topic

**`17-Sling-Model-Exporter`** — your syllabus point 26: what the Sling Model Exporter is, how `@Exporter` turns a model into JSON, the `.model.json` selector, how it relates to the SPA Editor, and where it fits alongside Content Fragments and GraphQL for headless delivery.

***

_Topic 16 of the AEM Interview Preparation repository. Teaching style, energy-sector project domain._
