Monday, June 2, 2025

Context-Aware Configuration (CAConfig) in AEM with WCM-IO – A Practical Guide

 

Context-Aware Configuration (CAConfig) in AEM with WCM-IO – A Practical Guide


context-aware configuration in aem


When building multi-language or multi-site Adobe Experience Manager (AEM) websites, you often need to apply site-specific or language-specific configurations.

For example, imagine you have an English site and an Arabic site. You may want different authentication settings, API keys, or UI labels based on which site the user visits. This is where Context-Aware Configuration (CAConfig) in AEM becomes incredibly useful.

It allows you to define configuration values at the site, language, or page level, and AEM automatically picks the correct values based on the page context.


Why Use Context-Aware Configuration in AEM?

CAConfig makes your code:

  • Flexible – define different settings for different sites or pages
  • Clean & Secure – no hardcoding values
  • Maintainable – easier for teams to update settings in /conf


Getting Started with CAConfig in AEM

  • Navigate to your core module in the AEM Maven project, and optionally create a config package (e.g., com.myproject.core.config).

  • Then create a Java interface, for example: MsalConfig.java.

 package com.adobe.aem.guides.inowate.core.config;

import org.apache.sling.caconfig.annotation.Configuration;
import org.apache.sling.caconfig.annotation.Property;

@Configuration(
label = "Inowate - Context Aware Configuration for MSAL",
description = "Context Aware Configuration for Inowate AEM Project"
)
public @interface MsalCaConfig {

@Property(     label = "Configuration Name",     description = "Name of the configuration context")
String configName() default "configName:";

@Property(     label = "Entra ID",     description = "Unique identifier for the application")
String entraID() default "entraID:";

@Property(     label = "Authority",     description = "Authorization server or token issuer URL")
String authority() default "authority:";
}

How to Use Context-Aware Configuration in Your AEM Component

Once your configuration interface is ready, the next step is to use it in your component where it’s needed.

For example, I have a component called TeamMember, and I want to access the configuration values defined via CAConfig and display them on the HTML output. For demonstration purposes, I’ll simply render the values in the 




 package com.adobe.aem.guides.inowate.core.models;
 import com.adobe.aem.guides.inowate.core.config.MsalCaConfig; //importing config here
 @Model(adaptables = { SlingHttpServletRequest.class,
Resource.class }, defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL)
public class TeamMembersModel {

private static final Logger LOGGER =      LoggerFactory.getLogger(TeamMembersModel.class);

@SlingObject
private Resource currentResource;

private String configName; // local veriables will use for config
private String entraID; // local veriables will use for config
private String authority; // local veriables will use for config
    
    @PostConstruct
    protected void init() {
if (currentResource != null) {
ConfigurationBuilder configBuilder             = currentResource.adaptTo(ConfigurationBuilder.class);
if (configBuilder != null) {
MsalCaConfig caConfig = configBuilder.as(MsalCaConfig.class);
if (caConfig != null) {
configName = caConfig.configName();
entraID = caConfig.entraID();
authority = caConfig.authority();
LOGGER.info("Loaded CAC: configName={},                 entraID={}, authority={}", configName, entraID, authority);
} else {
LOGGER.warn("CAConfig is null");
}
} else {
LOGGER.warn("ConfigurationBuilder is null");
}
}
    }
    // functions that will return the configs values.

    public String getConfigName() {
    return configName;
    }

    public String getEntraID() {
    return entraID;
       }

    public String getAuthority() {
    return authority;
    }

    }



Here, I’m simply rendering the configuration values in the HTML file for demonstration purposes.



Also, add the following code in /core/pox.xml in the <bnd> tag, adjust the code according to. Your project classes
 
 <bnd><![CDATA[
-plugin: org.apache.sling.caconfig.bndplugin.ConfigurationClassScannerPlugin,\
org.apache.sling.bnd.models.ModelsScannerPlugin
Sling-ContextAware-Configuration-Classes: \
com.adobe.aem.guides.inowate.core.config.MsalCaConfig
    Import-Package: javax.annotation;version=0.0.0,*

]]></bnd>

Deploying the Configuration

To deploy the configuration, run the following Maven commands:

  • mvn clean install -PautoInstallBundle -Padobe-public
  • mvn clean install -PautoInstallPackage -Padobe-public



Creating the Configuration in CRXDE Lite


  1. Navigate to /conf/projectname and create a folder named sling:configs. Make sure the folder’s primary type is set to sling:Folder.
  2. Inside sling:configs, create a new node with type nt:unstructured. Name this node exactly the same as your configuration interface file from the core module (for example, MsalConfig).

  3. Under this node, define the properties using the same field names as declared in your Java config interface. Assign appropriate values to these properties.

  4. To support multiple languages or sites (e.g., English and Arabic), create additional folders named en and ar, and copy the sling:configs structure into each. Then update the values based on the specific language or site requirements.

You can create as many language or site-specific folders as you need, based on your project requirements.

Refer to the screenshot below for a clear structure example.


/conf/inowate/sling:configs

sling:configs



/conf/inowate/en/sling:configs

sling:configs
/conf/inowate/ar/sling:configs

sling:configs

Linking Context-Aware Configuration to Your Sites

To apply your Context-Aware Configuration (CAConfig) to specific sites or pages, you'll need to set the sling:configRef property.

Navigate to the jcr:content node of the page where you want the configuration applied, and add the sling:configRef property. The value should be the path to the configuration you want to load.

In my setup:

  • I'm linking the general sling:configs to the language-masters site.
  • The /en configuration is linked to the English site.
  • The /ar configuration is linked to the Arabic site.

This allows AEM to automatically resolve and apply the correct configuration based on the context of the site or page being accessed.

Refer to the screenshots below for visual guidance.


For language-masters


For English site /content/inowate/language-masters/en

For Arabic site: /content/inowate/language-masters/en


So, when I load the English site page, AEM fetches the configuration from:

/conf/inowate/en/sling:configs

And when I load the Arabic site page, it pulls the configuration from:

/conf/inowate/ar/sling:configs

This ensures each language site uses its specific context-aware settings. Refer to the following screenshots for a clear example:

English Site Configuration Output:

Context-Aware Configurations


Arabic Site Configuration Output:
Context-Aware Configurations

Note: 

If you have another site, for example a German site, and you haven’t created specific Context-Aware Configurations for it, AEM will fall back to the default configuration located at: /conf/inowate/sling:configs

It won’t use the configurations from the en or ar folders, as those are specifically tied to the English and Arabic sites.



Context-Aware Configuration with WCM-IO Editor

Using the WCM-IO Editor, you can easily manage site-specific or page-specific Context-Aware Configurations (CA-Configs) in AEM. It simplifies the process of creating, updating, and maintaining CA-Configs through a user-friendly interface.

The initial steps remain the same as previously discussed. After that, you’ll need to install the WCM-IO package. This can be done by downloading the package and deploying it to AEM via CRXDE Lite.

Click here to download the WCM-IO package

Next, you’ll need to create a template, which will be used for creating your CA-Configuration page. You can create this template at the following path:

/apps/your-project/templates/template-name

Here’s the sample code for the template I’ll be using to create the CA-Configuration page:

 
 <?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0"
xmlns:cq="http://www.day.com/jcr/cq/1.0"
xmlns:jcr="http://www.jcp.org/jcr/1.0"
jcr:primaryType="cq:Template"
jcr:title="CAConfig Editor Page"
jcr:description="Template to edit context-aware configurations"
allowedPaths="[/content(/.*)]"
ranking="{Long}100">

<jcr:content
jcr:primaryType="cq:PageContent"
sling:resourceType="wcm-io/caconfig/editor/components/page/editor"
jcr:title="CAConfig Editor Page"/>
</jcr:root>


Screenshot from the code:


 After creating the template, make sure to include its path in the src/main/content/META-INF/vault/filter.xml file by adding the following entry:

<filter root="/apps/projectName/templates"/>




Now, run the following command to deploy the template to your AEM instance:

mvn clean install -PautoInstallPackage -Padobe-public


On CRXDLITE: 


Once the deployment is complete, let's say you have a German site and want to create a site-specific configuration for it.

To do this, go to CRXDE Lite, create a new folder named de under /conf/your-project/, and add the sling:configs node inside that folder then at the page level of your German site add sling:configRef  and assign the path to its until de folder. This will link the site to its specific context-aware configuration. Refer to the screenshots below for guidance.




 

Next, add the sling:configRef property to the jcr:content node of the German website page.






Creating a CA Configuration Page for the German Site

  • Navigate to the German site in AEM.
  • Select the German main page and click on the create button.
  • Choose the Configuration Template.
  • Enter a name for the configuration page and click Create.
  • Open the newly created page.
  • Click on the Configuration option.
  • Add the site-specific values you want for the German page.
  • Go to your German site page and refresh it.

You’ll now see that German-specific CA configurations are applied only to the German site.


Selecting the German page to create the CA config page


Create site specific ca page

selecting template
select CA - template

Adding the name of a page
name of CA - Page

Clicking on configuration 
Click on configuration inside ca page


Adding values for German page


update  CA values



Final output

german page final output with ca



Benefits of Using Context-Aware Configuration (CAConfig) in AEM

Custom Configs for Each Site or Language

You can easily set up different configurations for each website or language version — like English, Arabic, or German — without mixing things up.

Applies Configs Based on Page Location

AEM automatically picks the right configuration based on where the content lives, so there’s no need to write extra code to handle it manually.

All Configurations in One Place

Everything stays organised under the /conf folder, making it easier to manage and reuse across different components and pages.

Less Code, More Clarity

Since the logic lives in configuration, your components don’t need as many if-else checks, keeping the code clean and easier to maintain.

Perfect for Multi-Site Projects

If you're building for multiple brands or clients under one AEM instance, CAConfig helps you keep each one separate with its own set of rules.

Built-in Fallback Support

If a specific configuration isn’t found, AEM will automatically fall back to a default one — like global settings — so your site stays functional.

Secure and Easy for Authors

Configuration is separate from content, and tools like the wcm.io editor make it easy for non-developers to update values when needed.

Flexible Down to the Page Level

You can even have different settings for individual pages if needed — for example, one page could show a different layout or title than another.

Scales Well as You Grow

Whether you’re adding new regions, languages, or brands, CAConfig makes it simple to scale your setup without a mess.


Difference Between OSGi Configuration and Context-Aware Configuration (CAConfig) in AEM
OSGi Configuration

System-Level Settings

OSGi configs are mostly used for backend services and bundles — like setting up a connection to an external API, defining timeouts, or toggling a feature flag globally.

Applies Globally

Once set, the values apply across the whole AEM instance unless you're using run modes to split them.

Managed via Felix Console or Files

You typically manage OSGi configs through the Felix console (/system/console/configMgr) or deploy them from files under /apps or /libs.

Developer-Oriented

Mostly handled by developers or DevOps teams, not authors. Not very user-friendly for content teams. 


 Context-Aware Configuration (CAConfig)

Content-Level Settings

CAConfig is used when you need site-specific or page-specific settings, like setting a site title, map coordinates, or theme per language/site.

Applies Based on Context

It automatically picks the correct config based on where the content lives (e.g., /content/site/en vs /content/site/ar).

Stored Under /conf

All configurations live neatly under the /conf folder and can be edited through CRXDE or even via UI tools like wcm.io editor.

Author-Friendly

Authors or content admins can manage CAConfigs easily without touching code. It’s made for flexibility on the content side.


Conculusion

Context-Aware Configuration in AEM makes managing site- and language-specific settings simple and efficient. It helps keep your code clean and lets authors update configs easily without developer help. This approach is perfect for scaling multi-site projects smoothly. If you want flexible and maintainable configs, CAConfig is the way to go! 


Monday, April 21, 2025

How to Create and Map a System User in AEM (Step-by-Step Guide)

 In Adobe Experience Manager (AEM), when you build services or backend logic, you often need to access JCR (Java Content Repository) securely. For this, you don’t use regular users—you use System Users.





System Users are special, non-login users used for service-level operations. They don’t have passwords and are safer to use than admin or normal users.

Let’s walk through the steps to create and map a system user in AEM.


Step 1: Create a System User

  • Go to AEM Web Console: http://localhost:4502/crx/explorer/index.jsp
  • Log in with admin credentials.
  • Click on User Administration tab.



  • Click Create System User, and fill:
  • User ID: inowate-test-user
  • Add path. Click Create.(Under /home/system, create a folder for your project if not already created (example: /home/system/myproject). else you can create directly in system)
Note:  I'm assigning permissions to this folder because my contact form submissions will be stored in the JCR under this location. In your case, you should grant permissions to the folder where you intend to read, write, update, delete, or modify JCR nodes, depending on your specific requirements.


Check following screenshot from my practical work




Step 2: Assign Required Permissions

  • http://localhost:4502/useradmin
  • Search your system user: inowate-test-user
  • Select the user, and assign read/write permissions to specific paths your service will access. For example: (/content/myproject, /var/contact-form-submission)

Avoid giving unnecessary permissions. Check the following screenshot



Step 3: Map the User with a Service

  • http://localhost:4502/system/console/configMgr
  • search (Apache Sling Service User Mapper Service Amendment)
  • Add an entry like the following screenshot.


User System user in code

Now we can use system user in our code in servlet or in service where it required as per need
@Reference
private ResourceResolverFactory resolverFactory;

private ResourceResolver getServiceResourceResolver() {
    Map<String, Object> param = new HashMap<>();
    param.put(ResourceResolverFactory.SUBSERVICE, "my-service-name");
    try {
        return resolverFactory.getServiceResourceResolver(param);
    } catch (LoginException e) {
        log.error("Failed to get service resource resolver", e);
    }
    return null;
}


Conclusion

System users make your AEM services secure and clean. Just remember:

  • Create under /home/system
  • Use mapper config correctly
  • Give minimum permissions
  • Use getServiceResourceResolver() in your code



Thursday, February 27, 2025

How to Use Adobe AEM SCSS in UI.Frontend: A Simple Guide


 When to Use UI.Frontend in AEM

Imagine you’re building a custom theme for an AEM site. Here’s how UI. Frontend helps:

Organized Code: Use the styles folder to manage SCSS files for your theme, like _variables.scss for colors and fonts.

Efficient Builds: The dist folder ensures your compiled CSS and JS are ready for deployment.

Dynamic Assets: Store static images in resources and dynamic ones in DAM.

Scalability: As your project grows, you can add more folders and files without clutter.


Benefits

Fast Loading: Compiled SCSS and JS in the dist folder to ensure optimized, minified code for faster page loads.

Organized Assets: Proper folder structure helps search engines crawl your site efficiently.

Reusable Components: Component-specific SCSS and JS make it easier to maintain and update your site.








Folder Structure in UI.Frontend

The folder structure is key to organizing your SCSS, JS, and other assets. Here’s a breakdown of how it works:

complete folder structure

1. UI.Frontend

This is the main folder created by default when you set up an AEM project. It’s where all your front-end code lives.

2. Dist Folder

The dist folder is important. When you build your project (using commands like npm run prod), your CSS and JS files are compiled and placed here. From dist, these files move to ui.apps/clientlibs/(your clientlibs name) and then get exported to the AEM server.

Pro Tip: If you delete the dist folder, don’t worry! Just run the build command again, and it will recreate the folder with all your compiled SCSS and JS files.

3. ProjectName Folder

Inside the src folder, you can create a separate folder (like projectName) to keep all your SCSS, JS, and assets organized. Alternatively, you can use the default components and resources folders. In the screenshot, I’ve created a separate folder for better organization.

4. JS Folder

The js folder is where you store all your JavaScript files. If you’re using packages like Bootstrap, you can either:

  • Install them via npm and reference them in package.json.
  • Download the files manually and place them in js/global/. Both approaches have their benefits:
  • npm approach: Easier to manage and update packages.
  • Manual download: More control over specific versions and no dependency on npm.
manage files in js


5. Resources Folder

Use the resources folder for static assets like images that won’t change often. For dynamic assets (images that might change), use the AEM DAM (Digital Asset Management) folder.
Example:

  • From resources: background: url("../resources/images/dotted-pattern.svg");
  • From DAM: background-image: url(/content/dam/your-folder/img/common/Plus.svg);

6. Styles Folder

The styles folder is where your SCSS files live. You can organize it further:

  • styles/base: For global files like _variables.scss or package files like _bootstrap.min.scss.
  • styles/components: For component-specific SCSS files.

You can create more folders inside styles as needed. (Points 6, 7, and 8 from the Main SS are addressed here.)

manage file in style

7. main.js + main.scss

These are the entry points for your project:

  • In main.scss, import all your SCSS files. Start with package files (if using downloaded packages) and then your custom SCSS files.
  • In main.js, import main.scss at the top, followed by all your JS files.

Examples

in main.scss import syntax

in main.jsimport syntax



Important Configuration Files

  1. clintlib.config.js 

This file is a configuration file for AEM Client Libraries (ClientLibs), using aem-clientlib-generator to manage JavaScript, CSS, and other assets for Adobe Experience Manager (AEM). Let’s go through it step by step:


// path: A Node.js module used to handle and manipulate file paths.
// { dependencies } = require("webpack"): Extracts dependencies from Webpack, but this isn't actually used later in the file.
const path = require("path");
const { dependencies } = require("webpack");


// BUILD_DIR: The output directory where Webpack compiles assets (dist as we discssued above it contain our all complied css+js).
// CLIENTLIB_DIR: The directory inside the AEM project where the ClientLibs are stored (/apps/projectname/clientlibs .
const BUILD_DIR = path.join(__dirname, "dist");
const CLIENTLIB_DIR = path.join(
__dirname,
"..",
"ui.apps",
"src",
"main",
"content",
"jcr_root",
"apps",
"projectName",
"clientlibs"
);


// 1. allowProxy: true: Allows accessing the client libraries via /etc.clientlibs/ instead of /apps/eti/clientlibs/.
// 2. serializationFormat: "xml": Defines the format for ClientLibs in AEM (used in .content.xml files).
// 3. cssProcessor: ["default:none", "min:none"]: Disables CSS minification.
// 4. jsProcessor: ["default:none", "min:none"]: Disables JavaScript minification.

const libsBaseConfig = {
allowProxy: true,
serializationFormat: "xml",
cssProcessor: ["default:none", "min:none"],
jsProcessor: ["default:none", "min:none"],
};

// context: BUILD_DIR: Sets the build directory as the working context.
// clientLibRoot: CLIENTLIB_DIR: Specifies the target directory inside AEM where the client libraries
module.exports = {
context: BUILD_DIR,
clientLibRoot: CLIENTLIB_DIR,

// libs: An array containing multiple ClientLibs definitions.
libs: [

// This defines a ClientLib named clientlib-dependencies:
// categories: ["eti.dependencies"]: Used to include this ClientLib in AEM components.
// cwd: "clientlib-dependencies": Looks for assets inside the clientlib-dependencies folder.
// files: ["**/*.js"], ["**/*.css"]: Copies all JavaScript and CSS files.
{
...libsBaseConfig,
name: "clientlib-dependencies",
categories: ["projectName.dependencies"],
assets: {
// Copy entrypoint scripts and stylesheets into the respective ClientLib
// directories
js: {
cwd: "clientlib-dependencies",
files: ["**/*.js"],
flatten: false,
},
css: {
cwd: "clientlib-dependencies",
files: ["**/*.css"],
flatten: false,
},
},
},

// Defines a ClientLib named clientlib-site:
// categories: ["eti.site"]: Used to load this ClientLib in AEM components.
// dependencies: ["eti.dependencies"]: Ensures that clientlib-dependencies is loaded first.
// Also includes non-JS/CSS files in resources, ignoring JS and CSS
{
...libsBaseConfig,
name: "clientlib-site",
categories: ["projectName.site"],
dependencies: ["projectName.dependencies"],
assets: {
// Copy entrypoint scripts and stylesheets into the respective ClientLib
// directories
js: {
cwd: "clientlib-site",
files: ["**/*.js"],
flatten: false,
},
css: {
cwd: "clientlib-site",
files: ["**/*.css"],
flatten: false,
},

// Copy all other files into the `resources` ClientLib directory
resources: {
cwd: "clientlib-site",
files: ["**/*.*"],
flatten: false,
ignore: ["**/*.js", "**/*.css"],
},
},
},


// Defines ClientLib clientlib-projectName:
// categories: ["projectName-site"]: Used in AEM components.
// dependencies: ["projectName.dependencies"]: Ensures dependent scripts load first.
// Similar to clientlib-site, it includes JS, CSS, and other assets.
{
...libsBaseConfig,
name: "clientlib-projectName",
categories: ["projectName-site"],
dependencies: ["projectName.dependencies"],
assets: {
// Copy entrypoint scripts and stylesheets into the respective ClientLib
// directories
js: {
cwd: "clientlib-projectName",
files: ["**/*.js"],
flatten: false,
},
css: {
cwd: "clientlib-projectName",
files: ["**/*.css"],
flatten: false,
},

// Copy all other files into the `resources` ClientLib directory
resources: {
cwd: "clientlib-projectName",
files: ["**/*.*"],
flatten: false,
ignore: ["**/*.js", "**/*.css"],
},
},
},
],
};




2. webpack.common.js

webpack.common.js is used to store shared configurations like entry points, output, and loaders.

"use strict";

// node.j plugin
const path = require("path");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const TSConfigPathsPlugin = require("tsconfig-paths-webpack-plugin");
const CopyWebpackPlugin = require("copy-webpack-plugin");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const ESLintPlugin = require("eslint-webpack-plugin");

const SOURCE_ROOT = __dirname + "/src/main/webpack";

const resolve = {
extensions: [".js", ".ts"],
plugins: [
new TSConfigPathsPlugin({
configFile: "./tsconfig.json",
}),
],
};

module.exports = {
resolve: resolve,
// Defines the main entry file for your Project
entry: {
yourproject: SOURCE_ROOT + "/yourproject/main.js",
},

// Controls output structure (clientlib-yourproject/ vs clientlib-dependencies/)
// [name] dynamically gets replaced with the actual chunk name, so for the yourproject entry, Webpack generates:
// it will create file with this name inside dist like dist/clientlib-yourproject/yourproject.js
output: {
filename: (chunkData) => {
return chunkData.chunk.name === "dependencies"
? "clientlib-dependencies/[name].js"
: "clientlib-yourproject/[name].js";
},
path: path.resolve(__dirname, "dist"), // here we are point to dist folder as we discussed above
},
module: {
rules: [
{
test: /\.tsx?$/,
exclude: /node_modules/,
use: [
{
loader: "ts-loader",
},
{
loader: "glob-import-loader",
options: {
resolve: resolve,
},
},
],
},
{
test: /\.scss$/,
use: [
MiniCssExtractPlugin.loader,
{
loader: "css-loader",
options: {
url: false,
},
},
{
loader: "postcss-loader",
options: {
plugins() {
return [require("autoprefixer")];
},
},
},
{
loader: "sass-loader",
},
{
loader: "glob-import-loader",
options: {
resolve: resolve,
},
},
],
},
],
},
resolve: {
alias: {
swiper: path.resolve(__dirname, "node_modules", "swiper"),
},
},
plugins: [
/* will clean old files from the dist folder before generating new ones.
The CleanWebpackPlugin automatically deletes files from the dist folder_
because Webpack's output.path defines where the build files go */
new CleanWebpackPlugin(),

// Checks code quality
new ESLintPlugin({
extensions: ["js", "ts", "tsx"],
}),

//MiniCssExtractPlugin extracts CSS into a separate file inside
//dist/clientlib-emoney/ so that AEM can use it as a client library.
new MiniCssExtractPlugin({
filename: "clientlib-yourproject/[name].css",
}),

/*This plugin copies static files (like images, fonts, etc.) from the
source folder (emoney/resources) to dist/clientlib-emoney/ so
they can be used in the final build.*/
new CopyWebpackPlugin({
patterns: [
{
from: path.resolve(__dirname, SOURCE_ROOT + "/yourproject/resources"),
to: "./clientlib-yourproject/",
},
],
}),
],
stats: {
assetsSort: "chunks",
builtAt: true,
children: false,
chunkGroups: true,
chunkOrigins: true,
colors: false,
errors: true,
errorDetails: true,
env: true,
modules: false,
performance: true,
providedExports: false,
source: false,
warnings: true,
},
};


Conclusion

In conclusion, using UI.Frontend in AEM helps organize and manage front-end code efficiently. It ensures fast loading through optimized, minified CSS and JS files, and maintains a clear folder structure for scalability. Proper configuration files like `clintlib.config.js` and `webpack.common.js` further streamline the build process, making it easier to maintain and update the site.


Sunday, December 29, 2024

A Step-by-Step Guide to Adding Clientlibs to AEM Components and Working with SCSS | Adobe AEM

 Adobe Experience Manager (AEM) offers robust tools for developers to create highly customizable components. In this guide, we’ll show you how to add client libraries (clientlibs) to specific components in AEM and seamlessly integrate SCSS for styling. Let’s break it down step by step.



A Step-by-Step Guide to Adding
 Clientlibs to AEM Components and Working with SCSS

Structure of Component



How to Create a Component in AEM

Creating a component is the first step in building customized functionality in AEM. Here’s how you do it:

  1. Navigate to the desired folder where you want to create the component.
  2. Click on "Create" and select "Create Component from Dialog" from the dropdown menu.
  3. Fill in the details, such as:




  4. Click Next, and your component will be created.
  5. Rename the generated .jsp file to .html to use the HTL format for modern templating.




  6. Add a cq:dialog node for configuration:
    Click Create > Create Node, or
    Copy and paste the cq:dialog from an existing core component.
  7. Drag and drop your new component onto the page, and its contents will render.




How to Add Clientlibs to Specific Components in AEM

Client libraries are essential for adding styles and scripts to your AEM components. Follow these steps to create and link clientlibs:

1. Create the Clientlibs Folder

  1. Navigate to the component node in CRXDE Lite.
  2. Click on "Create" and select "Create Node".
  3. Name the node (e.g., clientlibs) and set its type to cq:ClientLibraryFolder.




2. Add Folders for CSS and JavaScript

  1. Inside the clientlibs folder:
    Create a folder named css and place all your CSS files inside.
    Create a folder named js and place all your JavaScript files inside.
  2. Add two files:
    css.txt: Import your CSS files (e.g., style.css).
    js.txt: Import your JS files (e.g., script.js).



3. Configure the Clientlibs Properties

  1. Select the clientlibs folder and add the following properties:
    categories: Assign a unique category name (e.g., mycomponent.styles).
    allowProxy: Set this to true for accessibility.

4. Include Clientlibs in Your HTML File

To link the clientlibs in your component, add the following code to your .html file:



code:

<sly data-sly-use.clientlib="/libs/granite/sightly/templates/clientlib.html">
    <sly data-sly-call="${clientlib.css @ categories='testScssClientlibs' }" />
</sly>
<h1 class="myClass">Test Scss Component is working</h1>
<sly data-sly-use.clientlib="/libs/granite/sightly/templates/clientlib.html">
   
    <sly data-sly-call="${clientlib.js @ categories='testScssClientlibs'}" />

</sly>

5. Verify Your Work

Reload your AEM page, and you should see your CSS and JS files successfully applied to the component.


How to Load Static Resources in a Component


To load static resources like images in AEM components, follow these steps:

  1. Create a folder named resources within your clientlibs directory.
  2. Place your images inside the resources folder.
  3. Use the path "/apps/emoney/components/site-components/TestScssCompo/test-scss-compo/clientlibs/resources/images/img1.png" to reference the image.
  4. This path can be used in both HTML and CSS files to load the image.





How to Use SCSS with AEM Components

For advanced styling, SCSS provides a cleaner and more maintainable approach compared to plain CSS. Here’s how to integrate SCSS into your AEM components.

1. Set Up Your Environment

  1. Install the VS Code AEM Sync extension for easy code management.

  2. Import your component from the AEM server:
    - Right-click the parent folder in VS Code.
    - Select "Import from Server".

  3. Install Sass globally using the following command:

    bash : npm install -g sass

2. Create and Compile SCSS

  1. Navigate to the css folder of your component.

  2. Create a new file named style.scss.

  3. Write your SCSS code and compile it to CSS with the following command:


    command : sass style.scss style.css
  4. The SCSS code will be converted to a style.css file, which is already linked to the component via clientlibs.

3. Export to AEM

After making changes, export the component back to AEM:

  1. Right-click your component in VS Code and select "Export to Server".
  2. Refresh the AEM page to see the updated styles.



Common Issues and Troubleshooting

Why Are My Clientlibs Not Loading?

  • Ensure that the allowProxy property is set to true.
  • Check that the categories name matches in both the clientlibs folder and your .html file.

How Can I Debug SCSS?

  • Use browser developer tools to inspect styles and ensure your compiled CSS is properly linked in css.txt.


Conclusion

This comprehensive guide covers everything you need to know about adding clientlibs to specific AEM components and integrating SCSS. By following these steps, you can build scalable, modular, and visually appealing components with ease.

If you found this guide helpful, don’t forget to share it with your peers. For more AEM tutorials and tips, bookmark this blog and stay updated!