AEM React SPA

AEM React SPA allow us to create single page application using JavaScript framework such as React or Angular.

Single Page Application allow us to rewrite page content without page refresh.

AEM React Component

ui.apps module contains React components having dialog to author component.

ui.frontend module allow us to define react component having html and CSS

Follow URL to read more about react component.

Component Creation

Follow below steps to create brand new AEM React custom component. This will help us to understand AEM React SPA component creation in detail. As part of this blog, we will be using existing OOTB AEM Guides — WKND SPA Project code base.

  1. Checkout Git repo using URL having branch React/latest or follow below 2nd step to create brand new AEM React SPA application.
  2. Hitting below maven archetype command will help us to create brand new AEM React SPA application:
mvn -B org.apache.maven.plugins:maven-archetype-plugin:3.2.1:generate \
 -D archetypeGroupId=com.adobe.aem \
 -D archetypeArtifactId=aem-project-archetype \
 -D archetypeVersion=35 \
 -D appTitle="Practice SPA React App" \
 -D appId="wknd-spa-react" \
 -D artifactId="aem-practice-spa.react" \
 -D groupId="com.practice.react" \
 -D frontendModule="react" \
 -D aemVersion="cloud"

3. Import project in Intellij or Eclipse.

4. In ui.core module create an interface for sling model and name it as TitleTextComponent.java having two properties as title and description.

package com.adobe.aem.guides.wknd.spa.react.core.models;

import com.adobe.cq.export.json.ComponentExporter;
public interface TitleTextComponent extends ComponentExporter{
    public String getTitle();
    public String getDescription();

}

5. In same ui.core module, implement above TitleTextComponent.java interface and create sling model as TitleTextComponentImpl.java to export JSON.

Inject two properties title and description as ValueMapValue as shown below:

package com.adobe.aem.guides.wknd.spa.react.core.models.impl;

import com.adobe.aem.guides.wknd.spa.react.core.models.CustomComponent;
import com.adobe.aem.guides.wknd.spa.react.core.models.TitleTextComponent;
import com.adobe.cq.export.json.ComponentExporter;
import com.adobe.cq.export.json.ExporterConstants;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.models.annotations.DefaultInjectionStrategy;
import org.apache.sling.models.annotations.Exporter;
import org.apache.sling.models.annotations.Model;
import org.apache.sling.models.annotations.injectorspecific.ValueMapValue;

@Model(
        adaptables = SlingHttpServletRequest.class,
        adapters = { CustomComponent.class, ComponentExporter.class },
        resourceType = TitleTextComponentImpl.RESOURCE_TYPE,
        defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL
        )
@Exporter(
        name = ExporterConstants.SLING_MODEL_EXPORTER_NAME,
        extensions = ExporterConstants.SLING_MODEL_EXTENSION
        )
public class TitleTextComponentImpl implements TitleTextComponent {

    @ValueMapValue
    private String title;

    @ValueMapValue
    private String description;

    static final String RESOURCE_TYPE = "wknd-spa-react/components/title-text-component";

    // This function is important to export JSON depending on resourcetype.
    @Override
    public String getExportedType() {
        return TitleTextComponentImpl.RESOURCE_TYPE;
    }


    @Override
    public String getTitle() {
        return title;
    }

    @Override
    public String getDescription() {
        return description;
    }
}

getExportedType() is an important function to export JSON depending on resourcetype.

6. In ui.apps module, create TitleText component under /apps/wknd-spa-react/components/title-text path to author/render Title and Description fields.

Below is the dialog of TitleText component created under to author Title and Description.

<?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"
  xmlns:nt="http://www.jcp.org/jcr/nt/1.0"
  jcr:primaryType="nt:unstructured"
  jcr:title="Properties"
  sling:resourceType="cq/gui/components/authoring/dialog">
    <content
        jcr:primaryType="nt:unstructured"
        sling:resourceType="granite/ui/components/coral/foundation/fixedcolumns">
        <items jcr:primaryType="nt:unstructured">
            <column
                jcr:primaryType="nt:unstructured"
                sling:resourceType="granite/ui/components/coral/foundation/container">
                <items jcr:primaryType="nt:unstructured">
                    <Title
                        jcr:primaryType="nt:unstructured"
                        sling:resourceType="granite/ui/components/coral/foundation/form/textfield"
                        fieldLabel="Title"
                        name="./title"/>
                    <description
                        jcr:primaryType="nt:unstructured"
                        sling:resourceType="granite/ui/components/coral/foundation/form/textfield"
                        fieldLabel="Description"
                        name="./description"/>
                </items>
            </column>
        </items>
    </content>
</jcr:root>

Note: .html file will not be part of this ui.apps title-text component as it will be coming/loading as part React component from ui.frontend

7. In ui.frontend module, Create React TitleText component under ui.frontend module as shown below:

8. Below is title-text react component to render view. Please read below inline comment as part of code to better understand.

import { MapTo } from '@adobe/aem-react-editable-components';
import DOMPurify from 'dompurify';
import React, { Component } from 'react';
import extractModelId from '../../utils/extract-model-id';

// This will help us to include TitleText component specific CSS
require('./TitleText.scss');

/**
 * Default Edit configuration for the Text component that interact with the Core Text component and sub-types
 *
 * @type EditConfig
 */
const TitleTextEditConfig = {

  emptyLabel: 'Title Text',

  /**
   * emptyLabel will be a component placeholder if nothing is 
   * authored or below values are false.
   */
  isEmpty: function(props) {
    return !props || !props.title || props.title.trim().length < 1;
  }
};

/**
 * Below is TitleText React component to render title 
 * and description as part of render() function.
 */
class TitleText extends Component {


  get textContent() {
    return <div className='title-text'>
            <h1>{this.props.title}</h1>
            <p>{this.props.description}</p>
           </div>;
  }

  render() {
    return this.props.title ? this.textContent : "test";
  }
}

/**
 * This component is map to wknd-spa-react/components/title-text 
 * resourceType to load JSON.
 * It will return TitleText component if it is authored and not empty else 
 * it will return TitleTextEditConfig default constant.
 */
export default MapTo('wknd-spa-react/components/title-text')(
  TitleText,
  TitleTextEditConfig
);

Import TitleText component as part of import-components.js file.

import ‘./TitleText/TitleText’;

Trigger a build and deploy latest code on AEM instance. Allow Title Text Component to drag and drop as part of editable template policy.

Drag and drop Title Text Component as shown below:

Click on Edit button to author Title Text Component:

Author Title and Description as shown below.

Click on done.

Below is the snapshot of authored TitleText component

Note

There are two important OOTB box js files App.js and index.js. These files will helps us to load authored components view on page.

Imran Khan

Specialist Master (Architect) with a passion for cutting-edge technologies like AEM (Adobe Experience Manager) and a proven track record of delivering high-quality software solutions.

  • Languages: Java, Python
  • Frameworks: J2EE, Spring, Struts 2.0, Hibernate
  • Web Technologies: React, HTML, CSS
  • Analytics: Adobe Analytics
  • Tools & Technologies: IntelliJ, JIRA

🌐 LinkedIn

📝 Blogs

📧 Imran Khan