AEM in 40 Days
CalendarPhase 3 · Building with the Archetype

Day 14 of 40

WKND: Component Basics

Authoring dialogs, how values persist, and your first Sling Model

~50 min read3 videos1 source page

By the end of today you should be able to

  1. Describe the four files that make up a component and what each does
  2. Explain how a dialog field maps to a JCR property
  3. Trace a value from dialog input, through the repository, to rendered markup
  4. Explain what cq:dialog, cq:editConfig and componentGroup control

Anatomy of a component

A component is a folder under /apps/<appId>/components/. At most it contains:

  • .content.xml — the cq:Component node: title, group, sling:resourceSuperType.
  • <name>.html — the HTL script that renders it.
  • _cq_dialog/.content.xml — the authoring dialog, defined in Granite UI.
  • _cq_editConfig.xml — editing behaviour: drop targets, listeners, toolbar actions.

A proxy component has only the first. A fully custom component has all four plus a Sling Model in core. Everything is content — even the dialog is just nodes, which is why you can inspect and modify it in CRXDE.

The authoring round trip

This is the loop worth internalising, because almost every component bug lives somewhere along it:

  1. An author drops the component onto a page. AEM creates a node with sling:resourceType = "wknd/components/title".
  2. They open the dialog. Granite UI renders the fields from _cq_dialog.
  3. Each field has a name like ./jcr:title. The leading ./ means "relative to this component's node".
  4. On save, a POST goes to the component's node and the Sling POST servlet writes jcr:title = "Welcome" as a property.
  5. On render, the Sling Model reads that property and HTL outputs it.
The mapping is direct

A dialog field named ./jcr:title becomes a property called jcr:title on the component node. No mapping layer, no schema. If a value is not showing up, open CRXDE and look at the node — you will usually see immediately that the property is missing, misnamed, or the wrong type.

A dialog, concretely

Granite UI dialogs are verbose but mechanical. Stripped to essentials:

<jcr:root jcr:primaryType="nt:unstructured"
    sling:resourceType="cq/gui/components/authoring/dialog"
    jcr:title="Title">
  <content sling:resourceType="granite/ui/components/coral/foundation/container">
    <items>
      <tabs sling:resourceType="granite/ui/components/coral/foundation/tabs">
        <items>
          <properties jcr:title="Properties">
            <items>
              <title
                sling:resourceType="granite/ui/components/coral/foundation/form/textfield"
                fieldLabel="Title"
                name="./jcr:title"/>
            </items>
          </properties>
        </items>
      </tabs>
    </items>
  </content>
</jcr:root>

Field types you will use constantly:

  • form/textfield, form/textarea, form/numberfield
  • form/pathfield — pick a page or asset
  • form/select — a dropdown, with options as child nodes or from a datasource
  • form/checkbox — note it needs a companion form/hidden field with @Delete so unchecking actually removes the property
  • form/multifield — a repeating group, stored as numbered child nodes

cq:editConfig

_cq_editConfig.xml controls how the component behaves in the editor, not how it renders. Two things you will actually reach for:

  • Drop targets — let an author drag an asset from the DAM directly onto the component, writing to a named property.
  • Refresh behaviourcq:listeners with afteredit="REFRESH_PAGE" forces a full page reload after editing, which you need when a component affects page-level markup.

Debugging the round trip

When a component shows nothing, walk the loop in order rather than guessing:

  1. Does the node exist, with the right sling:resourceType? (CRXDE)
  2. Did the dialog write the property, with the expected name? (CRXDE)
  3. Is the Sling Model registered and adapting? (/system/console/slingmodels)
  4. Is the HTL reading the field name you think it is?

Nine times out of ten step 2 answers it — a dialog field whose name lost its ./ prefix, or a typo in the property name.

Today's takeaway

Dialog field name → JCR property → Sling Model getter → HTL expression. Four links; when something is empty, find the broken link rather than rewriting the component.

Watch

Adobe's own videos for this topic. They load only when you press play.

Component Basics - Starter Project
Component Basics - Component Authoring
Component Basics - Sling Model

Read on Experience League

The primary sources these notes are drawn from.

Your notes

Saved automatically to this browser.

Check yourself

10 questions on today's material. 80% to pass.

Take the quiz