Editable Templates: How Every AEM Page Gets Its Structure
Structure, initial content, policies and layout mode — we build a template from scratch. No Java.
📺 Prefer to watch? Full episode, 5 live demos: 👉
But why was it allowed there? Something also decided the header can’t be touched, and that a new page isn’t empty.
That something is the template.
A template does three jobs
Structure — the fixed frame. Header, footer, locked on every page. Plus a container left open.
Initial content — what a new page starts with before anyone types.
Policies — which components are allowed in which container. The guest list.
Two are content. One is rules. Keep them separate and templates stop being confusing.
And three folders:
/apps → code. Components. Deployed by Maven.
/conf → configuration. Templates, template types, policies.
/content → pages.The two properties on every page
Select a page’s jcr:content in CRXDE:
cq:template = /conf/aeminsider/settings/wcm/templates/page-content
sling:resourceType = aeminsider/components/pagecq:template — the page remembers its template. Forever.
sling:resourceType is the one that holds AEM together. Content lives under /content, code under /apps, and this path is the only thing joining them: to render me, use that component. The Card had one. The Teaser had one. A page is just a node with a resource type.
Follow it and you’ll notice our page component has no page.html — only customheaderlibs.html and customfooterlibs.html. It inherits the real renderer via sling:resourceSuperType. How Sling walks that chain is next episode.
Inside the template itself:
page-content
├── structure ← what EVERY page shows
├── initial ← what NEW pages start with
└── policies ← which rules apply to which containerBuild one from scratch
Copy the page template type, rename it, and strip it to a bare root.
One gotcha: in an archetype project the type stores its policy inline — there’s no cq:policy to delete. You have to remove this from policies/jcr:content/root:
components = [ "group:AEM Insider Site - Content",
"/apps/aeminsider/components/form/container",
"group:AEM Insider Site - Structure" ]Miss it and your new template already allows components.
Create a template from your type and Structure mode opens completely empty — + says “no allowed components.” Assign a policy to root and the list wakes up. That’s what a policy does, in one click.
Then build top to bottom:
root
├── text ← header — locked (structure)
├── container ← content area — you UNLOCK this one
└── text ← footer — lockedDrag order in root = render order. And a new template is a Draft — a draft never shows in the Create Page wizard. Enable it.
Policies: the answer to last episode’s question
Give the unlocked container a policy and tick one group: AEM Insider Site - Content. That’s the group where the Card and the Teaser both live — remember componentGroup on them? This is what it was for.
You don’t have to tick whole groups, by the way. Expand one and every component has its own checkbox. You can mix both.
Now open the shipped Content Page template, select the inner container, read its ticked group. Same one. That checkbox is why the Card walked in — and why the Teaser walked in last episode.
The template holds only a pointer:
cq:policy = "aeminsider/components/container/<policy-node>"
← relative — resolved under
/conf/aeminsider/settings/wcm/policiesAnd the policy is just nodes:
policy_<generated>
├── jcr:title = "Article Page - Content"
└── components = [ "group:AEM Insider Site - Content" ]Everything you clicked became one line in that array.
One thing worth knowing: untick the group and the insert list empties — but components already on pages still render. A policy controls what authors can add, not what’s already there.
The rule of this episode
Add a Title and a Card to Initial Content and they land in the template’s initial node. Then run two experiments.
Create a new page: the title and card are already there, fully editable. Check an older page: still empty. The copy never reaches back.
Now edit the banner in Structure mode: every page changes instantly, without touching a single one.
Structure is live. Initial content is a copy. Structure → every page, now. Initial content → only pages created after it.
When a client asks you to “push this new block to all existing pages,” that’s not initial content. That’s structure, or a migration.
Export with Package Manager, filter /conf/aeminsider/settings/wcm. Honest note: real projects ship templates in code, in the ui.content package Maven built in EP03. Package Manager is the bridge.
Layout mode — and the bug worth knowing
Every container sits on a hidden 12-column grid. Layout mode gives each component drag handles, per breakpoint:
card/cq:responsive
├── default width=6 · offset=0 ← desktop: half of 12
└── phone width=12 · offset=0 ← phone: full widthOne setup step first: a freshly dragged Container is a Simple container and stacks everything. It has to be a Responsive Grid before widths do anything.
And now the gotcha. Breakpoints are declared in two places — the template (what the device bar reads) and grid.less (what actually renders). If they disagree, layout mode still saves. The node appears in CRXDE exactly as expected. Nothing moves on screen.
The archetype ships them misaligned. Stock grid.less:
@media (max-width: 768px) { /* phone */ }
@media (min-width: 769px) and (max-width: 1200px) { /* tablet */ }The editor’s tablet canvas is exactly 768px — which lands in phone, where a fresh component has no config, so it falls back to the desktop width. Shift it one pixel:
@media (max-width: 767px) { /* phone */ }
@media (min-width: 768px) and (max-width: 1200px) { /* tablet */ }WKND ships min-width: 768px. That’s the only reason the identical click works there.
So if a width does nothing: don’t debug the template. Check grid.less.
Recap
Three jobs: structure, initial content, policies
cq:templateremembers the template ·sling:resourceTypejoins content to codeStructure components are locked unless you unlock them
A policy is a guest list —
componentsis an array of groups and pathsPolicies govern what authors can add, not what already exists
Structure is live. Initial content is a copy.
Layout mode = 12 columns, stored per breakpoint in
cq:responsiveMake
grid.lessagree with the device bar
Editable templates keep a live link to their pages. Static templates hand over a copy and walk away — that’s the interview answer.
What’s next
You just followed a resource type to a super type to a script in another folder. How Sling actually does that is next episode: Sling Resource Resolution — types, super types, selectors, search paths.
🎥 This episode:
▶️ Full series: https://youtube.com/@aeminsider
🌐 Cheat sheets and decks:
https://aeminsider.com
⬅️ Previous — EP05, AEM Dialogs:
Stuck on a template? Hit reply and tell me where — I read every one.
This is AEM Insider. Straight talk on AEM.
Not affiliated with Adobe Inc.
