3.1 Core Components & Proxy Component Pattern
Key Takeaways
- The Proxy Component Pattern decouples authored content from Adobe base implementations by pointing sling:resourceSuperType to a versioned Core Component resource type such as core/wcm/components/teaser/v2/teaser.
- Content nodes in /content must always reference tenant-specific proxy components (e.g., myproject/components/teaser), never Core Component paths directly.
- Component dialogs are extended using the Sling Resource Merger (sling:hideChildren, sling:orderBefore), avoiding duplicative XML copying.
- Design dialogs (cq:design_dialog) configure template content policies under /conf, controlling allowed styles, heading tags, and feature toggles.
- Core Components employ explicit semantic versioning (/v1/, /v2/, /v3/) allowing legacy pages and modern features to coexist safely during phased migrations.
3.1 Core Components & Proxy Component Pattern
Exam Focus: Adobe WCM Core Components provide the modern foundation for AEM Sites development. The AD0-E128 exam heavily tests the Proxy Component Pattern (
sling:resourceSuperType), how to extend Core Components without modifying/apps/core/wcm, granular dialog merging via the Sling Resource Merger (sling:hideChildren,sling:orderBefore), content policy configuration via Design Dialogs (cq:design_dialog), component versioning conventions (/v1/,/v2/,/v3/), and composite component authoring.
The Philosophy of Adobe WCM Core Components
Historically, AEM developers built custom components from scratch or overlaid legacy "foundation" components located under /libs/foundation/components. This legacy approach introduced severe maintenance overhead: custom markup duplicated presentation logic across projects, upgrade cycles broke custom overlays, and accessibility standards required manual, error-prone remediation.
Adobe WCM Core Components represent a fundamental architectural paradigm shift. They are standardized, open-source building blocks designed specifically for modern AEM Sites development and AEM as a Cloud Service. The Core Components philosophy is governed by four core tenets:
- Separation of Presentation, Logic, and Configuration: Markup is written in pure HTML Template Language (HTL), business logic is encapsulated in Java Sling Models, and authoring interfaces are configured via Granite UI Coral 3 dialogs.
- Production-Ready & Enterprise Standards: Core Components ship out of the box with built-in compliance for WCAG 2.1 AA accessibility guidelines, responsive HTML5 markup, Search Engine Optimization (SEO) semantic tags, Accelerated Mobile Pages (AMP) support, and the AEM Style System.
- Extensibility without Modification: Components are designed to be extended cleanly through inheritance and delegation rather than direct code mutation.
- Seamless Upgradability: Component packages are versioned independently of project code, allowing continuous updates without breaking backwards compatibility.
Core Components are installed into /apps/core/wcm/components. However, web pages must never reference these paths directly.
The Proxy Component Pattern Architecture
The Proxy Component Pattern is the recommended architectural pattern for utilizing Core Components in AEM Sites. In this pattern, developers create "empty" or lightweight proxy components in their project-specific repository folder (e.g., /apps/myproject/components/content/teaser) whose sling:resourceSuperType property points to the corresponding Core Component version in /apps/core/wcm/components/teaser/v2/teaser.
+ /content/myproject/us/en/jcr:content/root/container/teaser
- sling:resourceType = "myproject/components/content/teaser" <-- Authored content references PROXY
+ /apps/myproject/components/content/teaser
- jcr:primaryType = "cq:Component"
- sling:resourceSuperType = "core/wcm/components/teaser/v2/teaser" <-- PROXY references CORE COMPONENT
+ /apps/core/wcm/components/teaser/v2/teaser
- teaser.html
- _cq_dialog
- _cq_design_dialog
Why the Proxy Pattern Is Recommended
If authored page nodes stored sling:resourceType="core/wcm/components/teaser/v2/teaser", severe architectural consequences would follow:
- Version Lock-in: Upgrading from Core Component
v2tov3would require querying, locking, updating, and republishing millions of authored JCR nodes across all sites. - Loss of Centralized Customization: Site-wide customizations (such as adding a custom tracking field to the dialog or altering CSS class wrappers) would have to be implemented across every individual content node or by modifying vendor code.
- Policy and Style System Detachment: Template content policies are mapped to the specific
sling:resourceTypeof the component. Changing the resource type invalidates all existing template policies and Style System assignments.
By proxying, the authored content path remains permanently stable (myproject/components/content/teaser). When an engineering team upgrades from v2 to v3, they only need to update a single string property (sling:resourceSuperType) on the proxy component definition in /apps.
Defining the Proxy Component in .content.xml
A proxy component requires minimal configuration. The following .content.xml defines a production-ready proxy for the Core Teaser component:
<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:jcr="http://www.jcp.org/jcr/1.0"
xmlns:cq="http://www.day.com/jcr/cq/1.0"
xmlns:sling="http://sling.apache.org/jcr/sling/1.0"
jcr:primaryType="cq:Component"
jcr:title="Teaser"
jcr:description="Displays a prominent visual teaser with image, title, description, and action link"
componentGroup="MyProject - Content"
sling:resourceSuperType="core/wcm/components/teaser/v2/teaser"/>
When Apache Sling processes a request for a page containing this component:
- Sling identifies
sling:resourceType="myproject/components/content/teaser". - Sling looks for a rendering script (such as
teaser.html) under/apps/myproject/components/content/teaser. - Because no script exists locally, Sling inspects
sling:resourceSuperType. - Sling traverses up the inheritance chain to
/apps/core/wcm/components/teaser/v2/teaserand executes the vendorteaser.htmlscript.
Why Custom Components Must Never Modify /apps/core/wcm
A common mistake among novice AEM developers is copying files into or directly editing /apps/core/wcm. In enterprise AEM architecture, modifying /apps/core/wcm is strictly forbidden for several reasons:
- Release Overwrites: The Core Components package (
core.wcm.components.all) is maintained by Adobe and deployed via Maven. Whenever a Service Pack, Cloud Service release, or Core Components maintenance release is deployed, all nodes under/apps/core/wcmare completely overwritten. Any local customizations made directly in that tree are irrevocably destroyed. - AEM as a Cloud Service Immutability: In AEMaaCS,
/appsand/libsare read-only at runtime. The immutable repository image is generated during the Cloud Manager build. Any manual JCR mutations in CRXDE Lite or via runtime packages are blocked. - Cloud Manager Code Quality Gate Violations: Cloud Manager pipelines execute strict OakPAL and FileVault validation scans. Modifying Adobe-owned paths triggers high-severity quality gate failures that halt production deployments.
All customizations must reside strictly within your project namespace (e.g., /apps/myproject/...).
Extending and Customizing Core Components
AEM offers four progressive tiers of component customization, ranging from pure configuration to custom rendering logic:
| Customization Tier | Technique | When to Use |
|---|---|---|
| 1. Pure Styling | Proxy + CSS + AEM Style System | Markup and dialog satisfy all functional needs; only visual presentation (colors, typography, spacing) requires branding. |
| 2. Dialog Customization | Sling Resource Merger (cq:dialog) | Adding project-specific fields (e.g., custom analytics tracking) or hiding standard tabs. |
| 3. Business Logic Customization | Sling Model Delegation (@Via(type = ResourceSuperType.class)) | Extending or manipulating backend data before rendering (e.g., formatting dates, fetching third-party CRM data). |
| 4. Markup Customization | HTL Script Override (teaser.html in proxy folder) | Radically restructuring DOM elements when CSS or Style System classes alone cannot achieve the required HTML layout. |
Exam Warning: Always prefer Sling Model Delegation over rewriting HTL scripts. Overriding HTL scripts severs your component from future upstream Core Component enhancements, security patches, and accessibility updates.
Dialog Customization via the Sling Resource Merger
Granite UI touch-optimized dialogs (cq:dialog) are rendered using the Sling Resource Merger. When a proxy component defines its own _cq_dialog node, Sling does not replace the inherited Core Component dialog entirely. Instead, Sling merges the proxy dialog tree over the supertype dialog tree.
Sling Resource Merger Directives
To manipulate inherited dialog tabs, containers, and fields, developers apply specialized resource merger properties:
sling:hideChildren: Suppresses specific child nodes or all child nodes (*). For example,sling:hideChildren="[link,asset]"hides the link and asset tabs.sling:hideProperties: Suppresses specific properties from an inherited node.sling:orderBefore: Re-orders the current node before a specified sibling node (e.g.,sling:orderBefore="asset").sling:hideResource="{Boolean}true": Completely removes an inherited node.
Practical Example: Adding a Custom Tab and Reordering Fields
Suppose we need to add a "Tracking" tab to our custom Teaser proxy dialog and order it before the standard "Asset" tab. We create _cq_dialog/.content.xml inside /apps/myproject/components/content/teaser/:
<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:jcr="http://www.jcp.org/jcr/1.0"
xmlns:nt="http://www.jcp.org/jcr/nt/1.0"
xmlns:cq="http://www.day.com/jcr/cq/1.0"
xmlns:sling="http://sling.apache.org/jcr/sling/1.0"
jcr:primaryType="nt:unstructured"
jcr:title="Teaser"
sling:resourceType="cq/gui/components/coral/common/tabs">
<content jcr:primaryType="nt:unstructured">
<tabs jcr:primaryType="nt:unstructured">
<items jcr:primaryType="nt:unstructured">
<!-- Custom tab injected via Resource Merger -->
<trackingTab
jcr:primaryType="nt:unstructured"
jcr:title="Campaign Tracking"
sling:resourceType="granite/ui/components/coral/foundation/container"
sling:orderBefore="asset">
<items jcr:primaryType="nt:unstructured">
<campaignId
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/form/textfield"
name="./campaignId"
fieldLabel="Campaign Tracking Code"
fieldDescription="Enter unique identifier for marketing attribution"/>
</items>
</trackingTab>
</items>
</tabs>
</content>
</jcr:root>
Because of the Sling Resource Merger, the standard tabs (Text, Link, Asset) remain intact, while our custom trackingTab is cleanly spliced in.
Design Dialogs (cq:design_dialog) & Content Policies
Understanding the distinction between an Author Dialog (cq:dialog) and a Design Dialog (cq:design_dialog) is critical for the exam:
- Author Dialog (
cq:dialog): Opened by content authors in the AEM Page Editor. Data entered here is stored directly on the authored component instance under/content/.../teaser. - Design Dialog (
cq:design_dialog): Opened by template authors and administrators in the Editable Template Editor. Data entered here is stored as a Content Policy under/conf/<myproject>/settings/wcm/policies/....
What Content Policies Control
Content policies allow administrators to govern how components behave across entire templates without modifying code. Examples include:
- Title Component Policy: Restricting allowed HTML heading elements (e.g., permitting only
<h2>,<h3>, and<h4>, while disallowing<h1>to enforce SEO standards). - Image Component Policy: Defining allowed WebP formats, maximum file upload sizes, and responsive image width presets.
- Teaser Component Policy: Enabling or disabling call-to-action buttons, requiring image assets, or toggling title delegation to the linked page.
- Style System: Mapping CSS classes to user-friendly UI toggles (e.g., "Dark Theme", "Featured Card").
Component Versioning Strategies
Core Components expose versioned resource types so multiple component versions can coexist:
/apps/core/wcm/components/title/v1/title/apps/core/wcm/components/title/v2/title/apps/core/wcm/components/title/v3/title
Use the explicit version path as the compatibility boundary and review the release notes before upgrading a proxy to a newer component version. New major component versions allow existing content to remain on its prior resource type during a phased migration.
Upgrading Components Safely
When a new Core Component version is released:
- Older versions are retained in the package. Existing sites continue functioning with zero regression risk.
- In your proxy component, update
sling:resourceSuperTypefromv2tov3. - If dialog property names changed between versions (for example,
./fileReferencemigrating to a structured child node), run an automated migration script on the JCR repository using the open-source AEM Core Components Migration Tool. - Test rendering and authoring in a lower environment before deploying to production.
Component Group Categorization (.content.xml)
In .content.xml, two properties govern how authors discover and interact with components:
jcr:title: The human-readable name displayed in the Page Editor side panel.componentGroup: The category grouping in the side panel component browser.
The .hidden Component Group
Setting componentGroup=".hidden" (or omitting the componentGroup property altogether) hides the component from the drag-and-drop component browser in the AEM Page Editor. This pattern is essential for:
- Internal Sub-Components: Components intended exclusively to be embedded programmatically via HTL
data-sly-resource. - Base / Abstract Components: Common parent components intended solely for inheritance via
sling:resourceSuperType. - Restricted Components: Components permitted only on specific templates via explicit policy whitelisting.
Embedding and Composing Core Components
Core Components are frequently assembled into composite components. For example, the Teaser component internally embeds and delegates behavior to:
- The Image component (handling responsive renditions and lazy loading).
- The Title component (handling heading tags and links).
Similarly, container components like Carousel, Tabs, and Accordion utilize the AEM Layout Container (responsivegrid) engine to manage child items dynamically. Authors can nest arbitrary components within individual accordion panels or carousel slides, while the parent container manages state, tab transitions, and ARIA accessibility roles.
Why must AEM developers implement the Proxy Component Pattern by referencing Core Components via sling:resourceSuperType rather than referencing Core Component paths directly in page content?
A developer wants to customize an author dialog (cq:dialog) inherited from a Core Component supertype. They need to hide an unneeded tab named 'link' without deleting or modifying any files under /apps/core/wcm. Which approach correctly utilizes the Sling Resource Merger?
In AEM Editable Templates, where are the design policy configurations defined by a component's cq:design_dialog (such as allowed heading tags or responsive image presets) persisted in the repository?
An AEM developer creates an internal card-body component that is designed exclusively to be embedded inside a composite card component via HTL data-sly-resource. Authors should never be able to drag and drop this component directly from the Page Editor side panel. How should this component be configured in its .content.xml?