Card Block
In this blog, we’ll be deep dive into the concept of blocks and their functionality, particularly within the realm of Edge Delivery Services. Before we begin, let’s first understand what blocks’ are. In the context of Adobe Experience Manager (AEM), blocks is a term used to refer to components.
Components are essentially the building blocks of a page, each serving a distinct purpose and carrying different content. They are the essential elements that together form a webpage, much like the individual pieces that come together to form a puzzle.
Within Edge Delivery Services, these components are referred to as blocks. The key role of these blocks is to load specific functionality accompanied by varying content, thereby enhancing the user experience and the overall performance of the webpage.
Now, let’s illustrate this with an example. Consider a webpage that we can divide into several blocks such as the header, footer, hero, image, and embed. Each block or component is independently responsible for a certain function. The header might contain the site’s main navigation, the footer might provide important links and information, the hero block could showcase featured content, the image block would handle graphical elements, and the embed block could manage embedded content like videos or social media posts.
Each of these blocks functions independently, allowing each part of the page to load its content separately. This modular approach offers a multitude of benefits, including faster load times, better site performance, and an enhanced user experience.
As part of current blog, we will try to understand one of the out-of-the-box cards block. How, we author a Card block as part of Google Doc and the way we render this component.
Below is the Cards block view we are planning to achieve as part of this block.
Below is the way we author any block component as part of any word or Google Doc where we provide name of the block and the classes we wants to have at root div:
Below is the way a block gets render on the page without block code in GitHub.
In the screenshot provided below, we can vividly see how the block content is authored in Google Doc and how it is subsequently rendered on the page in terms of its HTML representation.
The Card, highlighted in green, represents a block name. Using this block name, a parent div container is created, which bears the class name “card-container”. This is accompanied by a child div with the class “card-wrapper”, and an additional div element with the class “card”.
We have also defined “cards-body” and “custom-cards” as part of the block. These are nothing more than custom classes which we intend to add within the block, as highlighted in red below.
Each row will generate a parent div. In the case of the card block shown below, it has produced four parent divs, correlating with the four rows present.
In the current structure, each row is represented by two columns as illustrated below. The first column encompasses an image, while the second one houses a title and text.
Each row, which consists of two columns — the first containing an image and the second a title and text, automatically generates the following HTML structure. It’s worth noting that we already possess the necessary HTML structure, and we only need to apply some CSS to enhance its appearance into a four-column format.
Let’s proceed with creating the highlighted card block within the blocks folder. This will require both card.css and card.js files to achieve the desired block view.
Please Note: The card folder’s name must match the name provided to the block. Additionally, the names of the js and css files should precisely mirror the block folder’s name as shown below:
The card.js file provided below includes the out-of-the-box default decorate function, which is called as soon as the page loads. It’s worth noting that this decorate function is a default feature in every block js.
Please note: To gain a comprehensive understanding of how this function updates the block’s HTML structure and renders the name, it’s recommended to read the comments provided in each line of the code.
import { createOptimizedPicture } from '../../scripts/aem.js';
/*
block parameter name can be anything
representing default html snippet we discuss above.
*/
export default function decorate(block) {
/* change to ul, li */
/* Create ul tag dynamically */
const ul = document.createElement('ul');
/* loop through all child rows */
[...block.children].forEach((row) => {
/* Create ul tag dynamically */
const li = document.createElement('li');
/* Wrap every child element within li tag */
while (row.firstElementChild) li.append(row.firstElementChild);
/* loop through all div tags within li tag */
[...li.children].forEach((div) => {
/* append class to picture and content parent div */
if (div.children.length === 1 && div.querySelector('picture')) div.className = 'cards-card-image';
else div.className = 'cards-card-body';
});
/* append li to ul*/
ul.append(li);
});
/* get all img tags within ul and update properties*/
ul.querySelectorAll('img').forEach((img) => img.closest('picture').replaceWith(createOptimizedPicture(img.src, img.alt, false, [{ width: '750' }])));
// make block empty to removed ealier html code or structure.
block.textContent = '';
// append brand new updated HTML structure having ul and li's tags.
block.append(ul);
}
Below card.css will help us to apply styles on card block:
.card > ul {
list-style: none;
margin: 0;
padding: 0;
display: grid;
grid-template-columns: repeat(auto-fill, minmax(278px, 1fr));
grid-gap: 16px;
}
.card > ul > li {
border: 1px solid var(--dark-color);
background-color: var(--background-color)
}
.card .cards-card-body {
margin: 16px;
}
.card .cards-card-image {
line-height: 0;
}
.card .cards-card-body > *:first-child {
margin-top: 0;
}
.card > ul > li img {
width: 100%;
aspect-ratio: 4 / 3;
object-fit: cover;
}
Below is final card block will get render on page:
Imran Khan, Adobe Community Advisor, AEM certified developer and Java Geek, is an experienced AEM developer with over 11 years of expertise in designing and implementing robust web applications. He leverages Adobe Experience Manager, Analytics, and Target to create dynamic digital experiences. Imran possesses extensive expertise in J2EE, Sightly, Struts 2.0, Spring, Hibernate, JPA, React, HTML, jQuery, and JavaScript.