Skills for building AEM Edge Delivery Services sites — block development, content modeling, code review, testing, and page import.
82
76%
Does it follow best practices?
Impact
88%
1.04xAverage score across 6 eval scenarios
Advisory
Suggest reviewing before use
When creating local .plain.html files for testing blocks in the drafts/ folder, follow this structure to match how AEM Edge Delivery Services processes authored content.
The AEM CLI now automatically wraps HTML content with the headful structure (head, header, footer). When you create .plain.html files, you ONLY need to provide the section content.
What you create:
<div>...</div> (one per section)<div class="block-name"> with nested divsWhat the AEM CLI adds automatically:
<html>, <head>, <body> tags<header> and <footer> elements<main> wrapper<div>
<!-- Section 1: Mixed content - default content and a block -->
<h1>Page Heading</h1>
<p>This is regular paragraph content.</p>
<div class="block-name">
<!-- Block content goes here -->
<div>
<div>Block content cell 1</div>
<div>Block content cell 2</div>
</div>
</div>
<p>More content after the block.</p>
</div>
<div>
<!-- Section 2: Block in its own section -->
<div class="block-name variant-name">
<!-- Block content -->
</div>
</div>
<div>
<!-- Section 3: Multiple blocks in one section -->
<div class="block-one">
<!-- First block content -->
</div>
<div class="block-two">
<!-- Second block content -->
</div>
</div>IMPORTANT: HTML files must use the .plain.html extension:
drafts/hero-test.plain.htmldrafts/blocks/cards.plain.htmldrafts/hero-test.html (old format, no longer used)Start dev server with:
aem up --html-folder draftsPreview URLs:
drafts/hero-test.plain.html → URL: http://localhost:3000/drafts/hero-testdrafts/blocks/cards.plain.html → URL: http://localhost:3000/drafts/blocks/cardsdrafts/blog/index.plain.html → URL: http://localhost:3000/drafts/blog/ (NOT /drafts/)Content is organized into sections (top-level <div> elements).
<div>
<!-- Section 1 content -->
</div>
<div>
<!-- Section 2 content -->
</div>Important notes about sections:
Sections can include metadata to define styling and behavior using a special section-metadata div.
In HTML (using section-metadata div):
<div>
<div class="section-metadata">
<div>
<div>Style</div>
<div>dark</div>
</div>
</div>
<!-- Section content with dark background styling -->
</div>In markdown (Section Metadata table):
+------------------------------+
| Section Metadata |
+------------------+-----------+
| style | dark |
+------------------+-----------+How it works:
section-metadata div is placed at the beginning of a sectionsection-metadata div is removed from the DOMCommon section styles:
light - White or light backgrounddark - Dark background with light textgrey - Grey or off-white backgroundaccent - Branded color backgroundStyle naming best practices:
Example with multiple sections:
<!-- Section 1: Light background -->
<div>
<div class="section-metadata">
<div>
<div>Style</div>
<div>light</div>
</div>
</div>
<div class="hero">
<div><div><h1>Welcome</h1></div></div>
</div>
</div>
<!-- Section 2: Dark background -->
<div>
<div class="section-metadata">
<div>
<div>Style</div>
<div>dark</div>
</div>
</div>
<div class="cards">
<div>
<div>Card 1</div>
<div>Card 2</div>
</div>
</div>
</div>
<!-- Section 3: Light background (reuses "light") -->
<div>
<div class="section-metadata">
<div>
<div>Style</div>
<div>light</div>
</div>
</div>
<h2>About Our Company</h2>
<p>This section has default content, not blocks.</p>
</div>For guidance on identifying sections and assigning styles: Use the page-decomposition skill when migrating pages.
Sections can contain any combination of:
Regular HTML elements like headings, paragraphs, lists, etc.
<div>
<h1>Main Heading</h1>
<h2>Subheading</h2>
<p>Paragraph with <strong>bold</strong> and <em>italic</em> text.</p>
<ul>
<li>Unordered list item</li>
</ul>
<ol>
<li>Ordered list item</li>
</ol>
</div>Supported default elements:
<h1>, <h2>, <h3>, <h4>, <h5>, <h6><p><ul>, <ol>, <li><strong>, <em>, <a><picture> elements with <source> and <img> tags (see Images section below)<pre>, <code><blockquote>Blocks are <div> elements with specific class names that trigger decoration logic.
Basic block structure:
<div>
<div class="block-name">
<!-- Block content structured based on content model -->
</div>
</div>Block with variant:
<div>
<div class="block-name variant-name">
<!-- Block content -->
</div>
</div>Multiple variants:
<div>
<div class="block-name variant-one variant-two">
<!-- Block content -->
</div>
</div>Icons are authored using the :iconName: syntax and are processed into <span> elements with icon classes.
Author input:
:profile:HTML output:
<span class="icon icon-profile"></span>Important notes about icons:
/icons/ (e.g., :profile: → /icons/profile.svg)icon (base class) and icon-{name} (specific icon)Examples:
Icon in a link:
<a href="/profile"><span class="icon icon-profile"></span> View Profile</a>Icon with emphasis:
<strong><span class="icon icon-star"></span> Featured</strong>Icon by itself:
<p><span class="icon icon-home"></span></p>Images should always use the <picture> element with <source> elements for responsive images and format optimization.
Basic picture structure:
<picture>
<source type="image/webp" srcset="/media/image.jpg?width=2000&format=webply&optimize=medium" media="(min-width: 600px)">
<source type="image/webp" srcset="/media/image.jpg?width=750&format=webply&optimize=medium">
<source srcset="/media/image.jpg?width=2000&format=jpeg&optimize=medium" media="(min-width: 600px)">
<img loading="lazy" alt="Image description" src="/media/image.jpg?width=750&format=jpeg&optimize=medium">
</picture>Key aspects of picture elements:
<source> elements provide WebP format with fallbacksmedia attributes for responsive breakpoints (typically (min-width: 600px) for desktop)?width=750 for mobile, ?width=2000 for desktop)format and optimize=medium parameters for image optimization<img> element is the fallbackalt attribute for accessibilityloading="lazy" for images below the fold, loading="eager" for above-the-fold imagesStandard responsive breakpoints:
<picture>
<!-- WebP desktop (600px+) -->
<source type="image/webp" srcset="/media/image.jpg?width=2000&format=webply&optimize=medium" media="(min-width: 600px)">
<!-- WebP mobile -->
<source type="image/webp" srcset="/media/image.jpg?width=750&format=webply&optimize=medium">
<!-- JPEG desktop (600px+) -->
<source srcset="/media/image.jpg?width=2000&format=jpeg&optimize=medium" media="(min-width: 600px)">
<!-- JPEG mobile (fallback) -->
<img loading="lazy" alt="Descriptive alt text" src="/media/image.jpg?width=750&format=jpeg&optimize=medium">
</picture>Important notes:
/media/ folder or appropriate project locationalt text for accessibilityloading="eager" only for hero/above-the-fold imagescreateOptimizedPicture() JavaScript helper generates this structure automatically in decoration codeSimplified picture format for examples:
For brevity, examples in this document may show simplified picture tags:
<picture>
<img src="/media/image.jpg" alt="Description">
</picture>In actual test files, you can use either:
The internal structure of a block depends on its content model. Blocks typically use nested <div> elements to represent the table-like structure from authoring.
A hero block with an image and text:
<div class="hero">
<div>
<div>
<picture>
<img src="/media/hero-image.jpg" alt="Hero image description">
</picture>
</div>
</div>
<div>
<div>
<h1>Hero Heading</h1>
<p>Hero description text</p>
</div>
</div>
</div>A cards block with multiple items:
<div class="cards">
<div>
<div>
<picture>
<img src="/media/card1.jpg" alt="Card 1">
</picture>
</div>
<div>
<h3>Card 1 Title</h3>
<p>Card 1 description</p>
</div>
</div>
<div>
<div>
<picture>
<img src="/media/card2.jpg" alt="Card 2">
</picture>
</div>
<div>
<h3>Card 2 Title</h3>
<p>Card 2 description</p>
</div>
</div>
<div>
<div>
<picture>
<img src="/media/card3.jpg" alt="Card 3">
</picture>
</div>
<div>
<h3>Card 3 Title</h3>
<p>Card 3 description</p>
</div>
</div>
</div>The nested <div> structure in HTML corresponds to the table structure in authoring:
In document authoring (table):
| Block Name |
|-------------------|
| Cell 1 | Cell 2 |
| Cell 3 | Cell 4 |In HTML:
<div class="block-name">
<div> <!-- Row 1 -->
<div>Cell 1</div> <!-- Column 1 -->
<div>Cell 2</div> <!-- Column 2 -->
</div>
<div> <!-- Row 2 -->
<div>Cell 3</div> <!-- Column 1 -->
<div>Cell 4</div> <!-- Column 2 -->
</div>
</div>Here's a complete example of a test .plain.html file for a hero block:
File: drafts/hero-test.plain.html
<!-- Hero block section -->
<div>
<div class="hero">
<div>
<div>
<picture>
<img src="/media/hero-image.jpg" alt="Welcome to our site">
</picture>
</div>
</div>
<div>
<div>
<h1>Welcome to Our Site</h1>
<p>This is a compelling hero message that encourages visitors to take action.</p>
<p><a href="/contact">Get Started</a></p>
</div>
</div>
</div>
</div>
<!-- Regular content section -->
<div>
<h2>About This Test</h2>
<p>This page demonstrates the hero block in action.</p>
</div>
<!-- Hero block with variant -->
<div>
<div class="hero dark">
<div>
<div>
<picture>
<img src="/media/hero-dark.jpg" alt="Dark variant hero">
</picture>
</div>
</div>
<div>
<div>
<h2>Dark Variant Hero</h2>
<p>Testing the dark variant of the hero block.</p>
</div>
</div>
</div>
</div>Preview at: http://localhost:3000/drafts/hero-test
File location:
drafts/ folderdrafts/blocks/hero/test.plain.html.plain.html extensionRunning with local HTML:
aem up --html-folder draftsSection organization:
Images:
<picture> elements with proper responsive structure (see Images section)/media/ folder or appropriate locationalt attributes for accessibilityTesting considerations:
Content model alignment:
decorateMain in scripts.js) processes all contentblocks/{block-name}/{block-name}.js) processes individual blocksLocal HTML files are useful for quick iteration, but remember:
Always plan to create CMS content before finalizing your PR, even if you start with local HTML for rapid development.
evals
scenario-1
scenario-2
scenario-3
scenario-4
scenario-5
scenario-6
skills
analyze-and-plan
block-collection-and-party
block-inventory
building-blocks
code-review
content-driven-development
content-modeling
docs-search
find-test-content
generate-import-html
identify-page-structure
page-decomposition
page-import
preview-import
scrape-webpage
testing-blocks