AEM Insider
// AEM Insider · Video 4

Build Your First
AEM Component

No Java Needed · AEM Complete Tutorial Series 2026
Hands-On Demo · From CRXDE to an Authored Page
// Chapter 01 · CRXDE Lite

The Repository, Raw

Everything in AEM lives in the JCR — stored as nodes and properties. Once this clicks, AEM stops being magic.

Everything is a node

A folder that can also hold data. Pages, components, configs, images — all nodes.

Every node has properties

A name and a value. That's the entire data model of AEM.

Read and write

Create nodes, edit properties, write files — live on the instance.

localhost:4502/crx/de
# the content tree
/apps/aeminsider
├── components
├── clientlibs
└── i18n

# properties panel
jcr:primaryType  nt:folder
jcr:title        AEM Insider
// Chapter 02 · The Big Three

Three Folders That Matter

The repository and the codebase are mirrors — code is just content that gets deployed.

/apps/aeminsider
Your code

Components, rendering templates, client libraries. Deployed from ui.apps.

/content/aeminsider
The website

Pages, assets, everything authors create. From ui.content.

/conf/aeminsider
Configuration

Editable templates, policies, settings. Also from ui.content.

/libs is Adobe's own code. Rule #1 of AEM: never modify /libs. Look, learn, don't touch.

// Chapter 03 · Create the Component

One Node. Two Properties. One File.

Two ways to build: in CRXDE (instant — today's way) or in code (needs a deployment). A deployment overwrites CRXDE work — export it to code first.

/apps/aeminsider/components
card                 [cq:Component]
├── jcr:title        Card
├── componentGroup   AEM Insider
│                    Site - Content
└── card.html
cq:Component

Makes this folder a component — not just a folder.

jcr:title

The name authors see in the editor.

componentGroup

The entry ticket. It comes back later in this video.

Save All. In CRXDE, nothing exists until you hit Save All — every single change.

// Chapter 04 · The Dialog

The Author's Form

Authors don't use CRXDE — they need a form. And nobody writes dialogs from scratch: copy a working one, adapt it.

01 · Copy

The cq:dialog node from the helloworld component.

02 · Paste

Into our card component. Done — card has a dialog.

03 · Rename

Fields → ./title and ./description (as a textarea).

cq:dialog
cq:dialog            jcr:title Card
└── content / items / … / items
    ├── title
    │   fieldLabel  Title
    │   name        ./title
    └── description  [textarea]
        fieldLabel  Description
        name        ./description

name = ./title → saves the value as property "title", directly on the component's node.

// Chapter 05 · HTL

The Dialog Writes. HTL Reads.

Same name on both sides — that's the whole contract. No code in between.

card.html
<div class="cmp-card">
  <h2>${properties.title}</h2>
  <p>${properties.description}</p>
</div>
Same name, both sides

./title in the dialog ↔ properties.title in HTL.

Safe by default

HTL escapes output automatically — XSS protection built in, not bolted on.

No Java yet

Real logic lives in Sling Models — later in the series. This component doesn't need one.

// Chapter 06 · The Guest List

Deployed ≠ Available

"I built my component. Why can't I see it in the editor?" — the #1 question every new AEM developer asks.

The bouncer
The editable template

Pages are built on editable templates (they live in /conf). Every template decides which components are allowed in its containers.

The guest list
The policy

The layout container's policy lists allowed component groups. Our ticket: AEM Insider Site - Content — the group we set in step one.

Editable templates & policies get their own video later in the series — today we just walk through the door.

// Chapter 07 · Author It

The Payoff

New page. Real authoring. The fields we built in CRXDE five minutes ago.

01
Create a test page

Sites console → Create → Page. Template: Content Page. Title: "Component Test".

02
Drag the Card in

Component browser → filter "Card" → drop it into the container.

03
Author it

Open the dialog. Title + description. Save — and it renders.

Develop → Deploy → Allow → Author. Your daily loop as an AEM developer, from today on.

// Chapter 08 · Behind the Scenes

The Round Trip

The part most tutorials skip — what actually happened when the author hit save.

  • 01Dialog saves — name="./title" writes each field's value.
  • 02JCR writes — properties land on the card node under the page.
  • 03Sling resolves — sling:resourceType points back to our component.
  • 04HTL renders — ${properties.title} reads that exact node. HTML goes out.
the page's card node
# /content/aeminsider/…/component-test
#   /jcr:content/root/container/card
title               My First Component
description         Straight talk on AEM.
sling:resourceType  aeminsider/
                    components/card

Content lives in /content. The renderer lives in /apps. That separation is the heart of AEM.

// Chapter 09 · Style It

From 1995 to Card

A style block inside the file — scoped to the component class so nothing leaks into the page.

card.html — for today only
<style>
  .cmp-card {
    padding: 24px;
    border: 1px solid #ddd;
    border-radius: 8px;
    box-shadow: 0 2px 8px rgba(0,0,0,.08);
  }
  .cmp-card h2 { color: #D32F2F; }
</style>
Scope it

Everything under .cmp-card — no leaking styles into the rest of the page.

The honest note

A <style> tag in the component is fine for learning — it is not how real projects ship CSS.

// Chapter 09 · Continued

Clientlibs, in 60 Seconds

Why the inline style is temporary — three reasons.

Repeated

10 cards on a page = 10 copies of the exact same CSS.

Unoptimized

No bundling. No minification. Every byte ships raw.

Uncached

The browser can't cache your styles as one versioned file.

AEM's answer: client libraries — bundled, minified, versioned, loaded once per page. ui.frontend feeds exactly this system. Full video later in the series.

// Chapter 10 · Export It to Code

Make It Deployment-Proof

The next deployment would wipe our CRXDE work. Package Manager gets it into the codebase first.

01 · Create

crx/packmgr → Create Package: "card-component".

02 · Filter

Edit → Filters → /apps/aeminsider/components/card. The shopping list.

03 · Build + Download

AEM zips that repository path. The zip lands on your machine.

04 · Copy into ui.apps

Unzip → copy card → paste into …/jcr_root/apps/aeminsider/components. Commit.

card-component.zip — unzipped
jcr_root/
└── apps/aeminsider/components/card
    ├── .content.xml   ← the node
    ├── _cq_dialog/    ← cq:dialog
    │   └── .content.xml
    └── card.html

# cq: on the instance
# becomes _cq_ on disk

Exported + committed = every future deploy ships the card instead of deleting it.

// Chapter 11 · Recap

What You Actually Learned

01
Nodes + properties

CRXDE Lite is the raw repository. Everything in AEM is stored this way.

02
The big three

/apps = code · /content = data · /conf = config. Mirrors of the codebase.

03
The component

A cq:Component node + jcr:title + componentGroup + card.html.

04
The contract

name="./title" writes. ${properties.title} reads. Same name, both sides.

05
The guest list

Deployed ≠ available. The template's policy allows component groups.

06
The round trip

Dialog save → node properties → sling:resourceType → HTL → HTML.

Built in CRXDE to learn fast — then exported to ui.apps. Version-controlled. Deployment-proof.

// That's Video 4

Next: master the
dialog.

Video 5 → AEM Dialogs — Deep Dive · dropdowns, checkboxes, path pickers, rich text, tabs & validation

Subscribe so you don't miss it. Stuck? Component not showing up? Drop a comment — I read all of them.