All AEM as a Cloud Service skills: component development, Workflow model design, development, triggering, launchers, debugging, and triaging, Dispatcher config authoring, advisory, incident response, performance tuning, and security hardening, Rapid Development Environment (RDE) deployment, log inspection, snapshots, and troubleshooting via `aio aem rde`, Jackrabbit Oak query/index tuning (property, Lucene index definitions), and extracting/inventorying JCR queries (XPath, SQL2, QueryBuilder) across a codebase.
85%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
Low
Low-risk findings worth noting
A comprehensive guide to building maintainable, scalable component architectures in Adobe Experience Manager.
Most AEM projects fail at component reusability because:
/apps/mysite/clientlibs/clientlib-base/
├── tokens/
│ ├── _colors.scss # $color-primary, $color-secondary
│ ├── _typography.scss # $font-heading, $font-body, scale
│ ├── _spacing.scss # $space-xs, $space-sm, $space-md
│ └── _breakpoints.scss # $bp-mobile, $bp-tablet, $bp-desktopWhy it matters: One token change updates entire site. Without this, you're hunting through 200 files to change a brand color.
Don't reinvent — extend Adobe Core Components:
| Core Component | Your Extension | What You Add |
|---|---|---|
core/wcm/components/image | mysite/components/image | Brand-specific renditions, lazy-load config |
core/wcm/components/teaser | mysite/components/card | Card variants via style system |
core/wcm/components/container | mysite/components/section | Background options, spacing presets |
Sling Resource Merger approach:
<!-- /apps/mysite/components/image/.content.xml -->
<jcr:root
jcr:primaryType="cq:Component"
sling:resourceSuperType="core/wcm/components/image/v3/image"
componentGroup="MySite - Content"/>Organize by atomic design principles:
/apps/mysite/components/
├── atoms/
│ ├── button/ # Single CTA, no children
│ ├── icon/ # SVG sprite reference
│ └── badge/ # Labels, tags
├── molecules/
│ ├── card/ # Image + text + CTA
│ ├── form-field/ # Label + input + validation
│ └── breadcrumb/ # Navigation molecule
├── organisms/
│ ├── header/ # Logo + nav + search
│ ├── hero/ # Full-width showcase
│ └── product-grid/ # Collection display
├── templates/
│ └── layouts/ # Page structure containers
└── _shared/
├── models/ # Shared Sling Models
└── utils/ # HTL templates, helpers// Anti-pattern: 500-line model doing everything
@Model(adaptables = Resource.class)
public class MegaCardModel {
// 47 @ValueMapValue fields
// Complex conditional logic
// Formatting, validation, transformation all mixed
}// Pattern: Interface-based composition
@Model(adaptables = Resource.class,
adapters = Card.class,
defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL)
public class CardImpl implements Card, Linkable, Imageable {
@Self @Via(type = ResourceSuperType.class)
private Teaser coreTeaser; // Delegate to core
@ValueMapValue
private String cardVariant;
@Override
public Link getLink() {
return coreTeaser.getLink();
}
@Override
public String getVariantClass() {
return "card--" + StringUtils.defaultIfBlank(cardVariant, "default");
}
}The multiplier effect — 1 component × Style System = many variants without code:
// /apps/mysite/components/card/cq:design_dialog/.content.xml
{
"tabs": {
"styletab": {
"styles": {
"groups": [
{
"label": "Card Style",
"items": [
{ "label": "Default", "value": "card--default" },
{ "label": "Featured", "value": "card--featured" },
{ "label": "Minimal", "value": "card--minimal" },
{ "label": "Horizontal", "value": "card--horizontal" }
]
},
{
"label": "Card Size",
"items": [
{ "label": "Small", "value": "card--sm" },
{ "label": "Medium", "value": "card--md" },
{ "label": "Large", "value": "card--lg" }
]
}
]
}
}
}
}Result: 4 styles × 3 sizes = 12 visual variants, 1 component to maintain.
Create reusable dialog snippets:
<!-- /apps/mysite/components/_shared/dialogs/link-fields.xml -->
<linkFields jcr:primaryType="nt:unstructured">
<linkUrl
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/form/pathfield"
fieldLabel="Link URL"
name="./linkUrl"
rootPath="/content"/>
<linkTarget
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/form/checkbox"
text="Open in new tab"
name="./linkTarget"
value="_blank"
uncheckedValue="_self"/>
<linkAriaLabel
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/form/textfield"
fieldLabel="Accessibility Label"
name="./linkAriaLabel"/>
</linkFields>Include in any component dialog:
<items jcr:primaryType="nt:unstructured">
<linkGroup
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/include"
path="/apps/mysite/components/_shared/dialogs/link-fields.xml"/>
</items>| Anti-Pattern | Why It Hurts | Better Approach |
|---|---|---|
| One-off components | Each page request spawns new component | Extend existing, use Style System |
| Hardcoded breakpoints | Can't adapt to design changes | Use token variables |
| Logic in HTL | Untestable, unmaintainable | Move to Sling Models |
| Inline styles | Authors create inconsistency | Predefined style options only |
| Component per page type | Explosion of similar components | Composable containers |
| No component governance | Wild west, duplicates emerge | Component review in PR process |
1. Author/Designer requests new component
↓
2. Check: Can existing component + Style System solve this?
↓ No
3. Check: Can we extend a Core Component?
↓ No
4. Design review: Atomic design placement, token usage
↓
5. Build with full documentation
↓
6. Add to component library showcaseBuild a component showcase page (often called "Kitchen Sink" or "Pattern Library"):
| Metric | Without Library | With Library |
|---|---|---|
| Components built | 150 | 35 |
| Avg time per component | 16 hours | 20 hours (more robust) |
| Total component dev time | 2,400 hours | 700 hours |
| New page build time | 40 hours | 8 hours |
| Bug fix propagation | Manual per instance | Single fix, everywhere |
Net savings: 50-70% development time over project lifecycle
.tessl-plugin
skills
aem-rde
aem-workflow
code-assessment
content-distribution
create-component
assets
references
dispatcher
incident-response
references
dispatcher-foundation
performance-tuning
references
dispatcher-foundation
security-hardening
references
dispatcher-foundation
technical-advisory
references
dispatcher-foundation
workflow-orchestrator
references
dispatcher-foundation
ensure-agents-md
references
migration
references
dispatcher
legacy-ui
template-modernization
validation
scripts
dispatcher-tool
validate-migration