Summary |
Discusses how to create an Adobe Experience Manager multi-field component that supports a rich text editor and lets an AEM author drag images from the Content Finder and drop them into the component. This article covers the following points:
A special thank you to Dheeraj Khanna, a CQ Solution Architect for helping with this development article. This article creates a custom xtype as part of creating a larger AEM component. Before reading this article, it is recommended that you are familiar with creating a custom xtype. For information, see Creating your first Adobe Experience Manager custom xtype. |
Digital Marketing Solution(s) | Adobe Experience Manager (Adobe CQ) |
Audience |
Developer (intermediate) |
Required Skills |
JavaScript, CSS, HTML |
Tested On | Adobe Experience Manager 5.5, 5.6 |
Note:
Download the multifield component from the following link. This article explains how to build the component and the application logic. To see the Hero component, install this package and then configure the sidekick to show the Nook category in Design mode.
Once you install using package manager, you can access the page using this URL: http://localhost:4502/cf#/content/nook/en_US/homepage.html
Download
You can create an Adobe Experience Manager (AEM) multi-field component that supports a rich text editor and lets an AEM author drag images from the AEM Content Finder and drop them into the component. In addition, when creating an AEM component, you can define a custom xtype and use it in the component. The custom xtype is rendered in the component’s dialog and an AEM author enters value into the custom xtype controls during design time.
Note:
Developing a custom xtype is discussed within this development article.
The AEM component developed in this development article is used by the CQ parsys system and is placed onto the AEM sidekick. An AEM author can drag the component from the CQ sidekick onto an AEM page during design time.

The following illustration shows the component that is created by following this development article.

In the previous illustration, notice that an image is dragged from the AEM Content Finder onto the component. Also notice this component supports multiple tabs, where each tab contains different fields. For example, when the user clicks the Title tab, a new panel is displayed with an Add Item control.

When the user clicks Add Item, a Rich Text Editor (RTE) appears that lets the user enter text, as shown in the following illustration.


The following illustration shows the file structure of the AEM component that is developed in this article.

Section | Description |
A | The JS files that contain the JavaScript logic that defines a custom xtype. When defining a custom xtype, you use out-of-the-box xtype data types available with AEM (this is shown later in this development article). |
B | The cq:dropTargets node defines the drop zone that lets AEM authors drag images from the Content Finder and drop them onto the component (see the illustration shown at the start of the development article). The cq:inplaceEditing node (type cq:InplaceEditingConfig) defines an in place editing configuration for the component. The cq:listeners (node type cq:EditListenersConfig) defines what happens before or after an action occurs on the component. |
C | JCR nodes that belong to the component’s dialog. Notice that each node under the items node corresponds to a tab located in the component’s dialog. That is, there are seven tabs in the dialog:
|
D | JCR nodes that are used as plug-ins for the Rich Text Editor. |
This development article steps you through how to build this AEM component using a custom xtype, JavaScript, JCR nodes, and CSS files. Once you read through this article, you will have a solid understanding of how to build an AEM custom component, including how to develop a custom xtype.
Create an Experience Manager application folder structure that contains templates, components, and pages by using CRXDE Lite.

The following describes each application folder:
- application name: contains all of the resources that an application uses. The resources can be templates, pages, components, and so on.
- components: contains components that your application uses.
- page: contains page components. A page component is a script such as a JSP file.
- global: contains global components that your application uses.
- template: contains templates on which you base page components.
- src: contains source code that comprises an OSGi component (this development article does not create an OSGi bundle using this folder).
- install: contains a compiled OSGi bundles container.
To create an application folder structure:
- To view the CQ welcome page, enter the URL http://[host name]:[port] into a web browser. For example, http://localhost:4502.
- Select CRXDE Lite.
- Right-click the apps folder (or the parent folder), select Create, Create Folder.
- Enter the folder name into the Create Folder dialog box. Enter hook.
- Repeat steps 1-4 for each folder specified in the previous illustration.
- Click the Save All button.
Note:
You have to click the Save All button when working in CRXDE Lite for the changes to be made.
You can create a template by using CRXDE Lite. A template enables you to define a consistent style for the pages in your application. A template comprises of nodes that specify the page structure. For more information about templates, see Templates.
To create a template, perform these tasks:
1. To view the welcome page, enter the URL
2. Select CRXDE Lite.
3. Right-click the template folder (within your application), select Create, Create Template.
4. Enter the following information into the Create Template dialog box:
- Label: The name of the template to create. Enter
templateHook . - Title: The title that is assigned to the template.
- Description: The description that is assigned to the template.
- Resource Type: The component's path that is assigned to the template and copied to implementing pages. Enter hook/components/page/
templateHook . - Ranking: The order (ascending) in which this template will appear in relation to other templates. Setting this value to 1 ensures that the template appears first
in the list.
5. Add a path to Allowed Paths. Click on the plus sign and enter the following value: /content(/.*)?.
6. Click Next
7. Select OK on Allowed Children.
Components are re-usable modules that implement specific application logic to render the content of your
By default, a component has at least one default script, identical to the name of the component. To create a render component, perform these tasks:
1. To view the welcome page, enter the URL
2. Select CRXDE Lite.
3. Right-click /apps/hook/components/page, then select Create, Create Component.
4. Enter the following information into the Create Component dialog box:
- Label: The name of the component to create. Enter
templateHook . - Title: The title that is assigned to the component.
- Description: The description that is assigned to the template.
5. Select Next
6. Select OK on Allowed Children.
7. Open the
8. Enter the following HTML code.
<html> <%@include file="/libs/foundation/global.jsp" %> <cq:include script="/libs/wcm/core/components/init/init.jsp"/> <body> <h1>Here is where the component will go</h1> <cq:include path="par" resourceType="foundation/components/parsys" /> </body> </html>
After you setup the AEM folder structure, create the multifield component that uses a custom xtype. Perform these tasks using CRXDE Lite:
1. Right click on /apps/hook/components and then select New, Component.
2. Enter the following information into the Create Component dialog box:
- Label: The name of the component to create. Enter hero.
- Title: The title that is assigned to the component. Enter AEM Hero component.
- Description: The description that is assigned to the template. Enter AEM Hero component.
- Super Resource Type: Enter foundation/components/parbase.
- Group: The group in the side kick where the component appears. Enter Hook.
- Allowed parents: Enter */*parsys.
3. Click Ok.
Note:
The remaining part of this article talks about how to create the hero component that uses a custom xtype and allows an author to drag images from the AEM Content Finder. The hero.jsp file located at /apps/hook/components/hero/hero.jsp is populated with JavaScript logic later in this development article.
A dialog lets an author click on the component during design time and enter values that are used by the component. The component created in this development article lets a user drag an image from the AEM Content Finder onto the component (see the illustration shown at the start of this development article). Once set in the AEM component, the image then appears in the AEM web page.
To add a dialog to the hero component, perform these tasks:
1. Select /apps/hook/components/hero, right click and select Create, Create Dialog.
2. In the Title field, enter Hero Component.
3. Click Ok.
4. Delete the tab1 node under /apps/hook/components/hero/dialog/items/items.
Create the first tab in the dialog titled Style and Hero. The following illustration shows this tab in the CQ dialog.

You build the controls on this tab by setting JCR nodes and properties. Once done, your dialog nodes for this tab resembles the following illustration.

The options node corresponds to the Display Type drop-down control. Under the options node, there are children nodes named o1, o2, o3, and o4. These children nodes define the text values that are displayed in the Display Type drop down control.
To create the Style and Hero Image tab, perform these tasks:
1. Click on the following node: /apps/hook/components/hero/dialog/items/items.
2. Right click and select Create, Create Node. Enter the following values:
- Name: style
- Type: cq:Panel
3. Select the /apps/hook/components/hero/dialog/items/items/style node.
4. Add the following property to the style node.
Name | Type | Value | Description |
title | String | Style and Hero Image | Specifies the title displayed on the dialog tab. |
5. Select the /apps/hook/components/hero/dialog/items/items/style node.
6. Right click and select Create, Create Node. Enter the following values:
- Name: items
- Type: cq:WidgetCollection
7. Select the /apps/hook/components/hero/dialog/items/items/style/items node.
8. Right click and select Create, Create Node. Enter the following values:
- Name: type
- Type: cq:Widget
9. Add the following properties to the type node.
Name | Type | Value | Description |
anchor | String | 60% | An anchor that belongs to the component. |
fieldLabel | String | Display Type | Specifies the field label that is displayed. |
name | String | ./displayType | Specifies the name of the control. You can reference this value in component’s JavaScript file (hero.js) to get the value of this field. For example: <%String displayType = properties.get("displayType", String.class);%> |
type | String | select | Specifies the type of control. |
xtype | String | selection | Specifies the data type of the control. The value selection corresponds to the CQ.form.Selection xtype. For information, see Class CQ.form.Selection. |
10. Select /apps/hook/components/content/hero/dialog/items/items/style/items/type.
11. Right click and select Create, Create Node. Enter the following values:
- Name: options
- Type: cq:WidgetCollection
Note:
This node is responsible for defining the values that appear in the displayType selection field.
12. Select /apps/hook/components/hero/dialog/items/items/style/items/type/options.
13. Right click and select Create, Create Node. Enter the following values:
- Name: o1
- Type: nt:unstructured
14. Select the /apps/hook/components/hero/dialog/items/items/style/items/type/options/o1 node.
15. Add the following properties to the o1 node.
Name | Type | Value | Description |
text | String | Image on Left of Content | Specifies the text that is displayed. |
value | String | imageLeft | Specifies the corresponding value. |
16. Select /apps/hook/components/hero/dialog/items/items/style/items/type/options.
17. Right click and select Create, Create Node. Enter the following values:
- Name: o2
- Type: nt:unstructured
18. Select the /apps/hook/components/hero/dialog/items/items/style/items/type/options/o2 node.
19. Add the following properties to the o2 node.
Name | Type | Value | Description |
text | String | Image on Right of Content |
Specifies the text that is displayed. |
value | String | imageRight |
Specifies the corresponding value. |
20. Select /apps/hook/components/hero/dialog/items/items/style/items/type/options.
21. Right click and select Create, Create Node. Enter the following values:
- Name: o3
- Type: nt:unstructured
22. Select the /apps/hook/components/hero/dialog/items/items/style/items/type/options/o3 node.
23. Add the following properties to the o3 node.
Name | Type | Value | Description |
text | String | Image on Top of Content |
Specifies the text that is displayed. |
value | String | imageTop |
Specifies the corresponding value. |
24. Select /apps/hook/components/hero/dialog/items/items/style/items/type/options.
25. Right click and select Create, Create Node. Enter the following values:
- Name: o4
- Type: nt:unstructured
26. Select the /apps/hook/components/hero/dialog/items/items/style/items/type/options/o4 node.
27. Add the following properties to the o4 node.
Name | Type | Value | Description |
text | String | Image on Bottom of Content |
Specifies the text that is displayed. |
value | String | imageBottom |
Specifies the corresponding value. |
28. Select the /apps/hook/components/hero/dialog/items/items/style/items node.
29. Right click and select Create, Create Node. Enter the following values:
- Name: imageurl
- Type: cq:Widget
30. Add the following properties to the imageurl node.
Name | Type | Value | Description |
anchor | String | 60% | An anchor that belongs to the component. |
fieldLabel | String | Image Action Link | Specifies the corresponding value. |
name | String | ./imageurl | Specifies the name of the control. |
xtype | String | textfield | Specifies the data type of the control. This value corresponds to CQ.Ext.form.TextField. For information, see CQ.Ext.form.TextField. |
31. Select the /apps/hook/components/hero/dialog/items/items/style/items node.
32. Right click and select Create, Create Node. Enter the following values:
- Name: imagealttext
- Type: cq:Widget
33. Add the following properties to the imagealttext node.
Name | Type | Value | Description |
anchor | String | 60% | An anchor that belongs to the component. |
fieldLabel | String | Image Alt Text | Specifies the field label. |
name | String | ./imagealttext | Specifies the name of the control. |
xtype | String | textfield | Specifies the data type of the control. This value corresponds to CQ.Ext.form.TextField. For information, see CQ.Ext.form.TextField. |
34. Select the /apps/hook/components/hero/dialog/items/items/style/items node.
35. Right click and select Create, Create Node. Enter the following values:
- Name: image
- Type: cq:Widget
36. Add the following properties to the image node.
Name | Type | Value | Description |
cropParameter | String | ./imageCrop | Name of the form field used for posting the cropping rect. |
ddGroups | String[] | media | Groups involved in drag & drop (no default specified). |
fileNameParameter | String | ./fileName | Name of the form field used for posting the file name. |
fileReferenceParameter | String | ./fileReference | Name of the form field used for posting the file reference. |
height | Long | 300 | Height of the SmartImage component. |
mapParameter | String | ./imageMap | Name of the form field used for posting the image map data. |
name | String | ./file | The field's HTML name attribute. |
requestSuffix | String | .img.png | This suffix is used to get the processed version of an image. It is simply appended to the data path. |
rotateParameter | String | ./imageRotate | Name of the form field used for posting the rotation angle. |
title | String | Image | The title text to be used as innerHTML (html tags are accepted) to display in the panel header. |
xtype | String | html5smartimage | Specifies the data type of the control. The value selection corresponds to CQ.form.SmartImage. For information, see Class CQ.form.SmartImage. |
Create the second tab in the dialog named Title. The following illustration shows this tab in the CQ dialog.

You build the controls on this tab by setting nodes and properties. Once done, your dialog resembles the following illustration.

To create the title tab, perform these tasks:
1. Click on the following node: /apps/hook/components/hero/dialog/items/items.
2. Right click and select Create, Create Node. Enter the following values:
- Name: title
- Type: cq:Panel
3. Select the /apps/hook/components/hero/dialog/items/items/title node.
4. Add the following property to the title node.
5. Select the /apps/hook/components/hero/dialog/items/items/title node.
6. Right click and select Create, Create Node. Enter the following values:
- Name: items
- Type: cq:WidgetCollection
7. Select the /apps/hook/components/hero/dialog/items/items/title/items node.
8. Right click and select Create, Create Node. Enter the following values:
- Name: title
- Type: cq:Widget
9. Add the following properties to the title node.
Name | Type | Value | Description |
externalStyleSheets | String | /apps/hook/components/hero/clientlib/css/static.css | Specifies the CSS file to use. (This style sheet is created in a later step.) |
fieldLabel | String | Title | Specifies the field label that is displayed. |
name | String | ./title | Specifies the name of the control. You can reference this value in component’s JavaScript file (hero.js) to get the value of this field. |
xtype | String | multifield | Specifies the data type of the control. The value selection corresponds to CQ.form.MultiField. For information, see CQ.form.MultiField. |
10. Select the /apps/hook/components/hero/dialog/items/items/title/items/title node.
11. Right click and select Create, Create Node. Enter the following values:
- Name: fieldConfig
- Type: nt:unstructured
12. Select the /apps/hook/components/hero/dialog/items/items/title/items/title/fieldConfig node.
13. Add the following properties to the fieldConfig node.
Name | Type | Value | Description |
externalStyleSheets | String[] | /apps/hook/components/hero/clientlib/css/static.css | Specifies the CSS file to use. (This style sheet is created in a later step.) |
removeSingle ParagraphContainer |
Boolean | true | True if the paragraph element of texts that consist only of a single paragraph. |
xtype | String | richtext | Specifies the data type of the control. The value selection corresponds to CQ.form.RichText. For information, see CQ.form.RichText. |
14. Select the /apps/hook/components/hero/dialog/items/items/title/items/title/fieldConfig node.
15. Right click and select Create, Create Node. Enter the following values:
- Name: rtePlugins
- Type: cq:Widget
16. Select the /apps/hook/components/hero/dialog/items/items/title/items/title/fieldConfig/rtePlugins node.
17. Add the following properties to the rtePlugins node.
Name | Type | Value | Description |
path | String | /apps/hook/components/rteconfig/rtePlugins.infinity.json | The path to the rich text editor plugins. (These files are are developed later in this development article.) |
xtype | String | cqinclude | Pseudo xtype that includes widget definitions from a different path in the AEM JCR repository. |
Create the third tab in the dialog named Subtitle. The following illustration shows this tab in the CQ dialog.

You build the controls on this tab by setting nodes and properties. Once done, you dialog resembles the following illustration.

To create the subtitle tab, perform these tasks:
1. Click on the following node: /apps/hook/components/hero/dialog/items/items.
2. Right click and select Create, Create Node. Enter the following values:
- Name: subtitle
- Type: cq:Panel
3. Select the /apps/hook/components/hero/dialog/items/items/subtitle node.
4. Add the following property to the subtitle node.
5. Select the /apps/hook/components/hero/dialog/items/items/subtitle node.
6. Right click and select Create, Create Node. Enter the following values:
- Name: items
- Type: cq:WidgetCollection
7. Select the /apps/hook/components/hero/dialog/items/items/subtitle/items node.
8. Right click and select Create, Create Node. Enter the following values:
- Name: subtitle
- Type: cq:Widget
9. Add the following properties to the subtitle node.
Name | Type | Value | Description |
fieldLabel | String | Sub-Title | Specifies the field label that is displayed. |
name | String | ./subtitle | Specifies the name of the control. You can reference this value in component’s JavaScript file (hero.js) to get the value of this field. |
xtype | String | multifield | Specifies the data type of the control. The value selection corresponds to CQ.form.MultiField. For information, see CQ.form.MultiField. |
10. Select the /apps/hook/components/hero/dialog/items/items/subtitle/items/subtitle node.
11. Right click and select Create, Create Node. Enter the following values:
- Name: fieldConfig
- Type: nt:unstructured
12. Select the /apps/hook/components/hero/dialog/items/items/subtitle/items/subtitle/fieldConfig node.
13. Add the following properties to the fieldConfig node.
Name | Type | Value | Description |
externalStyleSheets | String[] | /apps/hook/components/hero/clientlib/css/static.css | Specifies the CSS file to use. (This style sheet is created in a later step.) |
removeSingle ParagraphContainer |
Boolean | true | True if the paragraph element of texts that consist only of a single paragraph. |
xtype | String | richtext | Specifies the data type of the control. The value selection corresponds to CQ.form.RichText. For information, see CQ.form.RichText. |
14. Select the /apps/hook/components/hero/dialog/items/items/subtitle/items/subtitle/fieldConfig node.
15. Right click and select Create, Create Node. Enter the following values:
- Name: rtePlugins
- Type: cq:Widget
16. Select the /apps/hook/components/hero/dialog/items/items/subtitle/items/subtitle/fieldConfig/rtePlugins node.
17. Add the following properties to the rtePlugins node.
Name | Type | Value | Description |
path | String | /apps/hook/components/rteconfig/rtePlugins.infinity.json | The path to the rich text editor plugins. (These files are are developed later in this development article.) |
xtype | String | cqinclude | Pseudo xtype that includes widget definitions from a different path in the AEM JCR repository. |
Create the fourth tab in the dialog named Description. The following illustration shows this tab in the CQ dialog.

You build the controls on this tab by setting nodes and properties. Once done, you dialog resembles the following illustration.

To create the description tab, perform these tasks:
1. Click on the following node: /apps/hook/components/hero/dialog/items/items.
2. Right click and select Create, Create Node. Enter the following values:
- Name: description
- Type: cq:Panel
3. Select the /apps/hook/components/hero/dialog/items/items/description node.
4. Add the following property to the description node.
Name | Type | Value | Description |
title | String | Description | Specifies the title displayed on the dialog tab. |
5. Select the /apps/hook/components/hero/dialog/items/items/description node.
6. Right click and select Create, Create Node. Enter the following values:
- Name: items
- Type: cq:WidgetCollection
7. Select the /apps/hook/components/hero/dialog/items/items/description/items node.
8. Right click and select Create, Create Node. Enter the following values:
- Name: description
- Type: cq:Widget
9. Add the following properties to the description node.
Name | Type | Value | Description |
fieldLabel | String | Description | Specifies the field label that is displayed. |
name | String | ./description | Specifies the name of the control. You can reference this value in component’s JavaScript file (hero.js) to get the value of this field. |
xtype | String | multifield | Specifies the data type of the control. The value selection corresponds to CQ.form.MultiField. For information, see CQ.form.MultiField. |
10. Select the /apps/hook/components/hero/dialog/items/items/description/items/description node.
11. Right click and select Create, Create Node. Enter the following values:
- Name: fieldConfig
- Type: nt:unstructured
12. Select the /apps/hook/components/hero/dialog/items/items/description/items/description/fieldConfig node.
13. Add the following properties to the fieldConfig node.
Name | Type | Value | Description |
externalStyleSheets | String[] | /apps/hook/components/hero/clientlib/css/static.css | Specifies the CSS file to use. (This style sheet is created in a later step.) |
removeSingle ParagraphContainer |
Boolean | true | True if the paragraph element of texts that consist only of a single paragraph. |
xtype | String | richtext | Specifies the data type of the control. The value selection corresponds to CQ.form.RichText. For information, see CQ.form.RichText. |
14. Select the /apps/hook/components/hero/dialog/items/items/description/items/description/fieldConfig node.
15. Right click and select Create, Create Node. Enter the following values:
- Name: rtePlugins
- Type: cq:Widget
16. Select the /apps/hook/components/hero/dialog/items/items/description/items/description/fieldConfig/rtePlugins node.
17. Add the following properties to the rtePlugins node.
Name | Type | Value | Description |
Path |
String | /apps/hook/components/rteconfig/rtePlugins.infinity.json | The path to the rich text editor plugins. (These files are are developed later in this development article.) |
xtype | String | cqinclude | Pseudo xtype that includes widget definitions from a different path in the AEM JCR repository. |
Create the fifth tab in the dialog named Footnote. The following illustration shows this tab in the CQ dialog.

You build the controls on this tab by setting nodes and properties. Once done, you dialog resembles the following illustration.

To create the footnote tab, perform these tasks:
1. Click on the following node: /apps/hook/components/hero/dialog/items/items.
2. Right click and select Create, Create Node. Enter the following values:
- Name: footnote
- Type: cq:Panel
3. Select the /apps/hook/components/hero/dialog/items/items/footnote node.
4. Add the following property to the footnote node.
5. Select the /apps/hook/components/hero/dialog/items/items/footnote node.
6. Right click and select Create, Create Node. Enter the following values:
- Name: items
- Type: cq:WidgetCollection
7. Select the /apps/hook/components/hero/dialog/items/items/footnote/items node.
8. Right click and select Create, Create Node. Enter the following values:
- Name: footnote
- Type: cq:Widget
9. Add the following properties to the footnote node.
Name | Type | Value | Description |
fieldLabel | String | Footnote | Specifies the field label that is displayed. |
name | String | ./footnote | Specifies the name of the control. You can reference this value in component’s JavaScript file (hero.js) to get the value of this field. |
xtype | String | multifield |
Specifies the data type of the control. The value selection corresponds to CQ.form.MultiField. For information, see CQ.form.MultiField. |
10. Select the /apps/hook/components/hero/dialog/items/items/footnote/items/footnote node.
11. Right click and select Create, Create Node. Enter the following values:
- Name: fieldConfig
- Type: nt:unstructured
12. Select the /apps/hook/components/hero/dialog/items/items/footnote/items/footnote/fieldConfig node.
13. Add the following properties to the fieldConfig node.
Name | Type | Value | Description |
externalStyleSheets | String[] | /apps/hook/components/hero/clientlib/css/static.css | Specifies the CSS file to use. (This style sheet is created in a later step.) |
removeSingle ParagraphContainer |
Boolean | true | True if the paragraph element of texts that consist only of a single paragraph. |
xtype | String | richtext | Specifies the data type of the control. The value selection corresponds to CQ.form.RichText. For information, see CQ.form.RichText. |
14. Select the /apps/hook/components/hero/dialog/items/items/footnote/items/footnote/fieldConfig node.
15. Right click and select Create, Create Node. Enter the following values:
- Name: rtePlugins
- Type: cq:Widget
16. Select the /apps/hook/components/hero/dialog/items/items/footnote/items/footnote/fieldConfig/rtePlugins node.
17. Add the following properties to the rtePlugins node.
Name | Type | Value | Description |
Path | String | /apps/hook/components/rteconfig/rtePlugins.infinity.json | The path to the rich text editor plugins. (These files are are developed later in this development article.) |
xtype | String | cqinclude | Pseudo xtype that includes widget definitions from a different path in the AEM JCR repository. |
Create the sixth tab in the dialog named Links. The following illustration shows this tab in the CQ dialog.

The links tab is based on a custom xtype that is created in this development article. That is, all three controls shown in the previous illustration are defined by a custom xtype.
The following illustration shows the dialog of the links tab.

Note:
The name of the custom xtype is ejstcustom.
1. Click on the following node: /apps/hook/components/hero/dialog/items/items.
2. Right click and select Create, Create Node. Enter the following values:
- Name: links
- Type: cq:Panel
3. Select the /apps/hook/components/hero/dialog/items/items/links node.
4. Add the following property to the links node.
5. Select the /apps/hook/components/hero/dialog/items/items/links node.
6. Right click and select Create, Create Node. Enter the following values:
- Name: items
- Type: cq:WidgetCollection
7. Select the /apps/hook/components/hero/dialog/items/items/links/items node.
8. Right click and select Create, Create Node. Enter the following values:
- Name: links
- Type: cq:Widget
9. Add the following properties to the links node.
Name | Type | Value | Description |
fieldLabel | String | Links | Specifies the field label that is displayed. |
name | String | ./links | Specifies the name of the control. You can reference this value in component’s JavaScript file (hero.js) to get the value of this field. |
xtype | String | multifield | Specifies the data type of the control. The value selection corresponds to CQ.form.MultiField. For information, see CQ.form.MultiField. |
10. Select the /apps/hook/components/hero/dialog/items/items/links/items/links node.
11. Right click and select Create, Create Node. Enter the following values:
- Name: fieldConfig
- Type: nt:unstructured
12. Select the /apps/hook/components/hero/dialog/items/items/links/items/links/fieldConfig node.
13. Add the following properties to the fieldConfig node.
Name | Type | Value | Description |
optionsProvider | String | Ejst.x3.provideOptions | Specifies the custom xtype for this field. |
xtype | String | ejstcustom | Specifies the name of the custom xtype. A custom xtype is defined by using JavaScript. Before this is successful, you have to register the custom xtype. (This is shown later in this development article.) |
Create the final tab in the dialog named Images. The following illustration shows this tab in the CQ dialog.

You build the controls on this tab by setting nodes and properties. Once done, your dialog resembles the following illustration.

To create the Images tab, perform these tasks:
1. Click on the following node: /apps/hook/components/hero/dialog/items/items.
2. Right click and select Create, Create Node. Enter the following values:
- Name: otherimages
- Type: cq:Panel
3. Select the /apps/hook/components/hero/dialog/items/items/otherimages node.
4. Add the following property to the otherimages node.
5. Select the /apps/hook/components/hero/dialog/items/items/otherimages node.
6. Right click and select Create, Create Node. Enter the following values:
- Name: items
- Type: cq:WidgetCollection
7. Select the /apps/hook/components/hero/dialog/items/items/otherimages/items node.
8. Right click and select Create, Create Node. Enter the following values:
- Name: image1
- Type: cq:Widget
9. Add the following properties to the image1 node.
Name | Type | Value | Description |
ddGroups | String[] | media | Groups involved in drag & drop (no default specified). |
fieldLabel | String | Image1 | Specifies the label of the control. |
fileNameParameter | String | ./image1/fileName | Name of the form field used for posting the file name. |
fileReferenceParameter | String | ./image1/fileReference | Name of the form field used for posting the file reference. |
height | Long | 100 | Height of the SmartImage component. |
name | String | ./image1/image1file | The field's HTML names attribute. |
sling:resourceType | String | foundation/components/image |
The Sling resource type. |
title | String | Image1 | The title text to be used as innerHTML (html tags are accepted) to display in the panel header. |
width | Long | 200 | Width of the SmartImage component. |
xtype | String | html5smartimage | Specifies the data type of the control. The value selection corresponds to CQ.form.SmartImage. For information, see Class CQ.form.SmartImage. |
10. Select the /apps/hook/components/hero/dialog/items/items/otherimages/items node.
11. Right click and select Create, Create Node. Enter the following values:
- Name: image2
- Type: cq:Widget
12. Add the following properties to the image2 node.
Name | Type | Value | Description |
ddGroups | String[] | media | Groups involved in drag & drop (no default specified). |
fieldLabel | String | Image2 | Specifies the label of the control. |
fileNameParameter | String | ./image2/fileName | Name of the form field used for posting the file name. |
fileReferenceParameter | String | ./image2/fileReference | Name of the form field used for posting the file reference. |
height | Long | 100 | Height of the SmartImage component. |
name | String | ./image2/image1file | The field's HTML names attribute. |
sling:resourceType | String | foundation/components/image |
The Sling resource type. |
title | String | Image2 | The title text to be used as innerHTML (html tags are accepted) to display in the panel header. |
width | Long | 200 | Width of the SmartImage component. |
xtype | String | html5smartimage | Specifies the data type of the control. The value selection corresponds to CQ.form.SmartImage. For information, see Class CQ.form.SmartImage. |
13. Select the /apps/hook/components/hero/dialog/items/items/otherimages/items node.
14. Right click and select Create, Create Node. Enter the following values:
- Name: image3
- Type: cq:Widget
15. Add the following properties to the image3 node.
Name | Type | Value | Description |
ddGroups | String[] | media | Groups involved in drag & drop (no default specified). |
fieldLabel | String | Image3 | Specifies the label of the control. |
fileNameParameter | String | ./image3/fileName | Name of the form field used for posting the file name. |
fileReferenceParameter | String | ./image3/fileReference | Name of the form field used for posting the file reference. |
height | Long | 100 | Height of the SmartImage component. |
name | String | ./image3/image1file | The field's HTML names attribute. |
sling:resourceType | String | foundation/components/image |
The Sling resource type. |
title | String | Image3 | The title text to be used as innerHTML (html tags are accepted) to display in the panel header. |
width | Long | 200 | Width of the SmartImage component. |
xtype | String | html5smartimage | Specifies the data type of the control. The value selection corresponds to CQ.form.SmartImage. For information, see Class CQ.form.SmartImage. |
Add the following JavaScript files to an AEM CQ:ClientLibraryFolder node:
- CustomWidget.js: defines the custom xtype that is used in the Links tab. The name of the custom xtype is ejstcustom.
- RichText.js: defines the rich text editor that is used in in the AEM component.
- Component.js: defines helper methods used by the component.
To add these JS and CSS files to your component, add a cq:ClientLibraryFolder node. After you create the node, set properties that allow the component script to find the CSS files and the JS files.
Create the required JS files to create the component. Place the JS files in a folder named js as shown in this illustration.

To develop a custom xtype, you can use a CQ.form.CompositeField instance, which is the base class for panels. A panel can include one or more form fields. For information, see class CQ.form.CompositeField.
In this example, the CustomWidget.js file contains application logic that is responsible for defining and registering a custom xtype.
// register xtype
CQ.Ext.reg("ejstcustom", Ejst.CustomWidget);
The component’s dialog references the custom xtype. The following file represents the CustomWidget.js file.
Ejst.CustomWidget = CQ.Ext.extend(CQ.form.CompositeField, { /** * @private * @type CQ.Ext.form.TextField */ hiddenField: null, /** * @private * @type CQ.Ext.form.TextField */ linkText: null, /** * @private * @type CQ.Ext.form.TextField */ linkHref: null, /** * @private * @type CQ.Ext.form.ComboBox */ linkType: null, /** * @private * @type CQ.Ext.form.TextField */ formPanel: null, constructor: function(config) { config = config || { }; var defaults = { "border": true, "layout": "table", "columns":4 }; config = CQ.Util.applyDefaults(config, defaults); Ejst.CustomWidget.superclass.constructor.call(this, config); }, // overriding CQ.Ext.Component#initComponent initComponent: function() { Ejst.CustomWidget.superclass.initComponent.call(this); //Hidden Field this.hiddenField = new CQ.Ext.form.Hidden({ name: this.name }); this.add(this.hiddenField); //DROP DOWN this.linkType = new CQ.form.Selection({ type:"select", cls:"customwidget-1", listeners: { selectionchanged: { scope:this, fn: this.updateHidden } }, optionsProvider: this.optionsProvider }); this.add(new CQ.Ext.form.Label({ cls:"customwidget-label", text: "Type"})); this.add(this.linkType); //Link Text this.linkText = new CQ.Ext.form.TextField({ cls:"customwidget-2", listeners: { change: { scope:this, fn:this.updateHidden } } }); this.add(new CQ.Ext.form.Label({ cls:"customwidget-label", text: "Text"})); this.add(this.linkText); //Link HREF Starts this.linkHref = new CQ.Ext.form.TextField({ cls:"customwidget-3", listeners: { change: { scope:this, fn:this.updateHidden } } }); this.add(new CQ.Ext.form.Label({ cls:"customwidget-label", text: "URL"})); this.add(this.linkHref); //Link HREF ends }, // overriding CQ.form.CompositeField#processPath processPath: function(path) { console.log("CustomWidget#processPath", path); this.linkType.processPath(path); this.linkType.processPath(path); }, // overriding CQ.form.CompositeField#processRecord processRecord: function(record, path) { console.log("CustomWidget#processRecord", path, record); this.linkType.processRecord(record, path); this.linkType.processRecord(record, path); }, // overriding CQ.form.CompositeField#setValue setValue: function(value) { var parts = value.split("\\"); //this.linkType.setValue(parts[0]); this.linkType.setValue(parts[0]); this.linkText.setValue(parts[1]); this.linkHref.setValue(parts[2]); this.hiddenField.setValue(value); }, // overriding CQ.form.CompositeField#getValue getValue: function() { this.getRawValue(); return this.getRawValue(); }, // overriding CQ.form.CompositeField#getRawValue getRawValue: function() { return this.linkType.getValue() + "\\" + this.linkText.getValue() + "\\" + this.linkHref.getValue(); }, // private updateHidden: function() { //alert('customwidget updatehidden'); this.hiddenField.setValue(this.getValue()); } }); // register xtype CQ.Ext.reg("ejstcustom", Ejst.CustomWidget); //------------------------------------------------------------------------------ Ejst.x3 = {}; Ejst.x3.provideOptions = function(path, record) { // do something with the path or record return [{ text:"Button", value:"button" },{ text:"Link", value:"link" }]; };
The RichText.js file contains application logic that defines the RichText editor. You can copy the RichText.js file from the following AEM JCR location:
/libs/cq/ui/widgets/source/widgets/form/RichText.js
Note:
You have to modify a line of code in the RichText.js file. For details, see http://aemfaq.blogspot.ca/2013/04/richtext-in-multifield-widget.html.
The components.js file contains helper methods that are used by the component. The following file represents the components.js file.
/* * Copyright 1997-2009 Day Management AG * Barfuesserplatz 6, 4001 Basel, Switzerland * All Rights Reserved. * * This software is the confidential and proprietary information of * Day Management AG, ("Confidential Information"). You shall not * disclose such Confidential Information and shall use it only in * accordance with the terms of the license agreement you entered into * with Day. */ var Ejst = {}; Ejst.toggleProperties = function(id, expand) { var box = CQ.Ext.get(id); var arrow = CQ.Ext.get(id + '-arrow'); if (expand || !box.hasClass('open')) { box.addClass('open'); arrow.update('«'); } else { box.removeClass('open'); arrow.update('»'); } }; Ejst.expandProperties = function(comp) { comp.refresh(); var id = comp.path.substring(comp.path.lastIndexOf('/')+1); Ejst.toggleProperties(id, true); };
Create the required CSS files to create the component. Place the CSS files in a folder named CSS as shown in this illustration.

/*#CQ .x-form-text.x-form-field.x-trigger-noedit { width:40px; }* /* widgets */ #CQ .customwidget-label { width:70px; margin-top:10px; margin-right:5px; margin-left:20px; font:normal 12px tahoma, arial, helvetica, sans-serif; } #CQ .customwidget-label-2 { width:70px; margin-top:10px; margin-right:5px; margin-left:20px; } #CQ .customwidget-1 { width:100px !important; margin-top:4px; margin-right:10px; } #CQ .customwidget-2 { width:190px; margin-top:4px; margin-right:10px; margin-left:5px; } #CQ .customwidget-3 { width:190px; margin-top:4px; margin-right:10px; margin-left:5px; }
/* parsys component */ div.par { clear: both; } div.parsys_column { height: 100%; width: 100%; float: left; border: 0; vertical-align:top; padding: 0; margin: 0; } div.section { /* Property added to avoid IE hasLayout issue on paragraphs see #20817 - IE6: div around Drag Components image not big enough */ zoom: 1; } div.parsys_column .section { overflow:hidden; width: 100%; } /* column control layouts */ div.cq-colctrl-cols {width: 100%; float: left; } div.cq-colctrl-default { width: 100%;} /* layout 0 : 50% 50% ( grid6 + grid6 ) */ div.cq-colctrl-lt0 { } div.cq-colctrl-lt0-c0 { width: 48%; margin-right:10px} div.cq-colctrl-lt0-c1 { width: 48%; margin-left: 10px} /* layout 1 : 33% 33% 33%( grid4 + grid4 + grid4 ) */ div.cq-colctrl-lt1 { } div.cq-colctrl-lt1-c0 { width: 32%; margin-right: 10px;} div.cq-colctrl-lt1-c1 { width: 32%; margin-left: 10px; margin-right: 10px;} div.cq-colctrl-lt1-c2 { width: 32%; margin-left: 10px; } /* layout 2: 16% 16% 16% 33% ( grid2.6 + grid2.6 + grid2.6 + grid4 ) */ div.cq-colctrl-lt2 { } div.cq-colctrl-lt2-c0 { width: 24%; margin-right: 10px;} div.cq-colctrl-lt2-c1 { width: 24%; margin-left: 10px; margin-right: 10px} div.cq-colctrl-lt2-c2 { width: 24%; margin-left: 10px; margin-right: 10px} div.cq-colctrl-lt2-c3 { width: 23%; margin-left: 10px } span.strikethrough { text-decoration:line-through; } #CQrte span.strikethrough { text-decoration:line-through; }
You have to add two text files to the clientlibs folder. These text files map to the JS file and the CSS file. The names of the text files are: css.txt and js.txt. The following shows the contents of the js.txt file.
#base=js
RichText.js
components.js
CustomWidget.js
The following shows the content of the css.txt file.
#base=css
components.css
static.css
- Right-click /apps/hook/components/hero then select New, Node.
- Make sure that the node type is cq:ClientLibraryFolder and name the node clientlibs.
- Right click on clientlibs and select Properties. Add the two properties specified in the previous table to the node.
- Right click on clientlibs and select Create, Create Folder. Name the folder js.
- Right click on the js folder and select Create, Create File. Create the three files: RichText.js, components.js, and CustomWidget.js. Add the code specified in this article to each file.
- Right click on clientlibs and select Create, Create Folder. Name the folder css.
- Right click on the css folder and select Create, Create File. Create the two CSS files: components.css and static.css. Add the code specified in this article to each file.
- Add a TXT file to the clientlibs folder named js.txt. Add the content specified in this section.
- Add a TXT file to the clientlibs node named css.txt. Add the content specified in this section.
You can configure the component’s edit behavior by adding a node of type cq:EditConfig below the hero component. You determine the component’s behavior by setting child nodes and properties. For more information, see Configuring the Edit Behaviour of a Component.
The component specifies the drop target for dragging an image from the AEM content finder to the image. To define a drop target, you use a node of type cq:DropTargetConfig. The following illustration shows the cq:EditConfig node that belongs to the hero component.

To add a cq:EditConfig node to the component, perform these tasks:
1. Select /apps/hook/components/hero, right click and select Create, Create Node.
2. Enter the following values:
- Name: cq:EditConfig
- Type: cq:EditConfig
3. Click Ok.
Define the cq:dropTargets node. This node defines a list of drop targets that accept a drop from an asset of the content finder. To define the cq:dropTargets node, perform these tasks:
1. Click on the following node: /apps/hook/components/hero/cq:editConfig.
2. Right click and select Create, Create Node. Enter the following values:
- Name: cq:dropTargets
- Type: nt:unstructured
3. Select the /apps/hook/components/hero/cq:editConfig/cq:dropTargets node.
4. Right click and select Create, Create Node. Enter the following values:
- Name: image
- Type: cq:DropTargetConfig
5. Add the following properties to the image node.
Name | Type | Value | Description |
accept | String[] | image/.* | List of mime types accepted by this drop target; e.g. ["image/*"] |
groups | String[] | media | List of drag and drop groups that accept a source. |
propertyName | String | ./image/fileReference | Name of the property used to store the reference. |
6. Select the /apps/hook/components/hero/cq:editConfig/cq:dropTargets/image node.
7. Right click and select Create, Create Node. Enter the following values:
- Name: parameters
- Type: nt:unstructured
8. Add the following property to the parameters node.
Name | Type | Value | Description |
sling:resourceType | String | foundation/components/textimage | Specifies the sling resource type. |
9. Select the /apps/hook/components/hero/cq:editConfig/cq:dropTargets/image/parameters node.
10. Right click and select Create, Create Node. Enter the following values:
- Name: image
- Type: nt:unstructured
11. Add the following property to the image node.
Name | Type | Value | Description |
sling:resourceType | String | foundation/components/image | Specifies the sling resource type. |
12. Select the /apps/hook/components/hero/cq:editConfig/cq:dropTargets node.
13. Right click and select Create, Create Node. Enter the following values:
- Name: image1
- Type: cq:DropTargetConfig
14. Add the following properties to the image1 node.
Name | Type | Value | Description |
accept | String[] | image/.* | List of mime types accepted by this drop target; e.g. ["image/*"] |
groups | String[] | media | List of drag and drop groups that accept a source. |
propertyName | String | ./image1/fileReference | Name of the property used to store the reference. |
15. Select the /apps/hook/components/hero/cq:editConfig/cq:dropTargets/image1 node.
16. Right click and select Create, Create Node. Enter the following values:
- Name: parameters
- Type: nt:unstructured
17. Add the following property to the parameters node.
Name | Type | Value | Description |
sling:resourceType | String | foundation/components/textimage | Specifies the sling resource type. |
18. Select the /apps/hook/components/hero/cq:editConfig/cq:dropTargets/image1/parameters node.
19. Right click and select Create, Create Node. Enter the following values:
- Name: image1
- Type: nt:unstructured
20. Add the following property to the image1 node.
Name | Type | Value | Description |
sling:resourceType | String | foundation/components/image |
Specifies the sling resource type. |
The cq:inplaceEditing node (node type cq:InplaceEditingConfig) defines an inplace editing configuration for the component. To define the cq:InplaceEditingConfig node, perform these tasks:
1. Click on the following node: /apps/hook/components/hero/cq:editConfig.
2. Right click and select Create, Create Node. Enter the following values:
- Name: cq:inplaceEditing
- Type: cq:InplaceEditingConfig
3. Add the following property to the cq:inplaceEditing node.
Name | Type | Value | Description |
sling:resourceType | String | foundation/components/image | Specifies the sling resource type. |
The cq:listeners node (node type cq:EditListenersConfig) defines what happens before or after an action on the component. To define the cq:EditListenersConfig node, perform these tasks:
1. Click on the following node: /apps/hook/components/hero/cq:editConfig.
2. Right click and select Create, Create Node. Enter the following values:
- Name: cq:listeners
- Type: cq:EditListenersConfig
3. Add the following property to the cq:listeners node.
Name | Type | Value | Description |
afteredit |
String | REFRESH_PAGE |
The handler is triggered after the component is edited. |
This AEM component contains a Rich Text Editor. When the user clicks on a tab and then clicks the Add Item control, a Rich Text Editor is displayed as shown in this illustration.

The Rich Text Editor provides authors with a wide range of functionality for editing their textual content; providing them with icons, selection boxes and menus for a WYSIWYG experience. For more information, see Configuring the Rich Text Editor.
To configure the AEM RTE, you build JCR nodes and properties, similar to building a component dialog (that you performed earlier in this development article). The following illustration shows the JCR nodes that controls the behaviour of the AEM RTE.

To configure the AEM RTE, perform these tasks:
1. Select /apps/hook/components, right click and and then select New, Component.
2. Enter the following information into the Create Component dialog box:
- Label: The name of the component to create. Enter rteconfig.
- Title: The title that is assigned to the component. Enter rteconfig.
- Description: The description that is assigned to the template. Enter rteconfig.
3. Click OK.
4. Select /apps/hook/components/rteconfig.
5. Right click and select Create, Create Node. Enter the following values:
- Name: rtePlugins
- Type: nt:unstructured
6. Add the following properties to the rtePlugins node.
Name | Type | Value | Description |
removeSingleParagraphContainer | Boolean | true | You can keep the RTE from surrounding your text with tags by setting the removeSingleParagraphContainer property to true as long as you only create one paragraph. This property excludes the default <p> tag in the RTE. |
singleParagraphContainerReplacement | String | "" | RTE uses as a container for complete html that you enter by default until you use removeSingleParagraphContainer or singleParagraphContainerReplacement. |
Miscellaneous tools allow you to enter special characters or edit the HTML source. Special characters can be made available to your rich text editor; these might vary according to your installation. For example, consider the following illustration.

Create the misctools nodes by performing these tasks:
1. Select the following node: /apps/hook/components/rteconfig/rtePlugins.
2. Right click and select Create, Create Node. Enter the following values:
- Name: misctools
- Type: nt:unstructured
3. Add the following property to the misctools node.
Name | Type | Value | Description |
features | String | * | Defines which features of the plugin are activated. You may provide a String value of "*" to enable all features. |
4. Select the following node: /apps/hook/components/rteconfig/rtePlugins/misctools.
5. Right click and select Create, Create Node. Enter the following values:
- Name: specialCharsConfig
- Type: nt:unstructured
6. Select the following node: /apps/hook/components/rteconfig/rtePlugins/misctools/specialCharsConfig.
7. Right click and select Create, Create Node. Enter the following values:
- Name: chars
- Type: nt:unstructured
8. Select the following node: /apps/hook/components/rteconfig/rtePlugins/misctools/specialCharsConfig/chars.
9. Right click and select Create, Create Node. Enter the following values:
- Name: pound
- Type: nt:unstructured
10. Add the following property to the pound node.
Name | Type | Value | Description |
entity |
String | £ |
Specifies the HTML representation of the required character. |
11. Select the following node: /apps/hook/components/rteconfig/rtePlugins/misctools/specialCharsConfig/chars.
12. Right click and select Create, Create Node. Enter the following values:
- Name: nbsp
- Type: nt:unstructured
13. Add the following property to the nbsp node.
Name | Type | Value | Description |
features | String |   |
Specifies the HTML representation of the required character. |
14. Select the following node: /apps/hook/components/rteconfig/rtePlugins/misctools/specialCharsConfig/chars.
15. Right click and select Create, Create Node. Enter the following values:
- Name: registered
- Type: nt:unstructured
16. Add the following property to the registered node.
Name | Type | Value | Description |
features | String | ® | Specifies the HTML representation of the required character. |
17. Select the following node: /apps/hook/components/rteconfig/rtePlugins/misctools/specialCharsConfig/chars.
18. Right click and select Create, Create Node. Enter the following values:
- Name: copyright
- Type: nt:unstructured
19. Add the following property to the copyright node.
Name | Type | Value | Description |
features | String | © |
Specifies the HTML representation of the required character. |
20. Select the following node: /apps/hook/components/rteconfig/rtePlugins/misctools/specialCharsConfig/chars.
21. Right click and select Create, Create Node. Enter the following values:
- Name: trademark
- Type: nt:unstructured
22. Add the following property to the trademark node.
Name | Type | Value | Description |
features | String | ™ |
Specifies the HTML representation of the required character. |
23. Select the following node: /apps/hook/components/rteconfig/rtePlugins/misctools/specialCharsConfig/chars.
24. Right click and select Create, Create Node. Enter the following values:
- Name: emDash
- Type: nt:unstructured
25. Add the following property to the emDash node.
Name | Type | Value | Description |
features | String | — |
Specifies the HTML representation of the required character. |
You can create basic editing functions (cut, copy, paste) as a plugin. Create the edit node by performing these tasks:
1. Select the following node: /apps/hook/components/rteconfig/rtePlugins.
2. Right click and select Create, Create Node. Enter the following values:
- Name: edit
- Type: nt:unstructured
3. Add the following properties to the edit node.
Name | Type | Value | Description |
defaultPasteMode | String | plaintext | Default mode when pasting is executed using the Ctrl + V key or the main paste button (defaults to "wordhtml"). |
stripHtmlTags | Boolean | true | True if HTML tags should be stripped off before inserting it on paste. |
You can create simple character formatting (bold, italic, underlined) as a plugin. Create the justify node by performing these tasks:
1. Select the following node: /apps/hook/components/rteconfig/rtePlugins.
2. Right click and select Create, Create Node. Enter the following values:
- Name: justify
- Type: nt:unstructured
3. Add the following properties to the justify node.
Name | Type | Value | Description |
features | String | * |
Defines which features of the plugin are activated. You may provide a String value of "*" to enable all features. |
You can create find and replace functionality as a plugin. Create the findreplace node by performing these tasks:
1. Select the following node: /apps/hook/components/rteconfig/rtePlugins.
2. Right click and select Create, Create Node. Enter the following values:
- Name: findreplace
- Type: nt:unstructured
3. Add the following property to the findreplace node.
Name | Type | Value | Description |
features | String | * |
Defines which features of the plugin are activated. You may provide a String value of "*" to enable all features. |
You can create spellcheck functionality as a plugin. Create the spellcheck node by performing these tasks:
1. Select the following node: /apps/hook/components/rteconfig/rtePlugins.
2. Right click and select Create, Create Node. Enter the following values:
- Name: spellcheck
- Type: nt:unstructured
3. Add the following property to the spellcheck node.
Name | Type | Value | Description |
features | String | * |
Defines which features of the plugin are activated. You may provide a String value of "*" to enable all features. |
You can create sub and superscript functionality as a plugin. Create the subsuperscript node by performing these tasks:
1. Select the following node: /apps/hook/components/rteconfig/rtePlugins.
2. Right click and select Create, Create Node. Enter the following values:
- Name: subsuperscript
- Type: nt:unstructured
3. Add the following property to the subsuperscript node.
Name | Type | Value | Description |
features | String | * |
Defines which features of the plugin are activated. You may provide a String value of "*" to enable all features. |
You can create styling text fragments with a CSS class (using "span" tags) functionality as a plugin. In this example, a Strike Through style is specified. This results in the Strike Through being an available option in the RTE Style dropdown as shown in the following illustration.

Create the styles node by performing these tasks:
1. Select the following node: /apps/hook/components/rteconfig/rtePlugins.
2. Right click and select Create, Create Node. Enter the following values:
- Name: styles
- Type: nt:unstructured
3. Add the following properties to the styles node.
Name | Type | Value | Description |
features | String | * |
Defines which features of the plugin are activated. You may provide a String value of "*" to enable all features. |
4. Select the following node: /apps/hook/components/rteconfig/rtePlugins/styles.
5. Right click and select Create, Create Node. Enter the following values:
- Name: styles
- Type: cq:WidgetCollection
6. Select the following node: /apps/hook/components/rteconfig/rtePlugins/styles/styles.
7. Right click and select Create, Create Node. Enter the following values:
- Name: strikethrough
- Type: nt:unstructured
8. Add the following properties to the strikethrough node.
Name | Type | Value | Description |
cssName | String | strikethrough | Specifies CSS name. |
Text | String | Strike Through | The text that is displayed in the Style dropdown. |
Modify the hero JPS file to include JavaScript logic. The Java script contains application logic to display values entered into the components dialog. Included in the JavaScript is application logic to display the image that is dragged from the AEM Content Finder to the image dialog. The following code fragment shows the JavaScript logic that renders the image that is dragged from the AEM content finder.
<b> Hero Image:</b>
<br>
<%
Image img = new Image(resource);
img.setSelector(".img");
img.setDoctype(Doctype.fromRequest(request));
img.setAlt("image alt text");
img.draw(out);
%>
<br><br>
Add the following JavaScript to the hero.jsp file located at the following location: /apps/hook/components/hero/hero.jsp.
<%@include file="/libs/foundation/global.jsp"%> <cq:includeClientLib categories="hook.components" /> <%@ page import="com.day.cq.commons.Doctype, com.day.cq.wcm.foundation.Image, com.day.cq.wcm.api.components.DropTarget, com.day.cq.wcm.api.components.EditConfig, com.day.cq.wcm.commons.WCMUtils, org.apache.jackrabbit.commons.JcrUtils" %> <br> ---------------------------------- <br> <b> HERO HOOK COMPONENT: </b> <br> ---------------------------------- <br> <br> <%String displayType = properties.get("displayType", String.class);%> <b> Display Type: </b><cq:text property="jcr:text" value="<%= displayType %>" /> <br> <%String imageurl = properties.get("imageurl", String.class);%> <b> URL: </b><cq:text property="jcr:text" value="<%= imageurl %>" /> <br> <%String imagealttext = properties.get("imagealttext", String.class);%> <b> Alt Text: </b><cq:text property="jcr:text" value="<%= imagealttext %>" /> <br> <br> <b> Hero Image:</b> <br> <% Image img = new Image(resource); img.setSelector(".img"); img.setDoctype(Doctype.fromRequest(request)); img.setAlt("image alt text"); img.draw(out); %> <br><br> ------------------------------- <br> <b>TITLE:</b> <br> <c:forEach var="title" items="${properties.title}"> ${title} <br> </c:forEach> <br><br> ------------------------------- <br> <b>SUB TITLE:</b> <br> <c:forEach var="subtitle" items="${properties.subtitle}"> ${subtitle} <br> </c:forEach> <br><br> ------------------------------- <br> <b>DESCRIPTION:</b> <br> <c:forEach var="description" items="${properties.description}"> ${description} <br> </c:forEach> <br><br> ------------------------------- <br> <b>FOOT NOTE:</b> <br> <c:forEach var="footnote" items="${properties.footnote}"> ${footnote} <br> </c:forEach> <br><br> ------------------------------- <br> <b> LINKS TAB:</b> <br><br> <% Node node = null; if(resource.adaptTo(Node.class)!=null) { node=resource.adaptTo(Node.class); PropertyIterator props=null; if (node.getProperties()!=null) props = node.getProperties(); while (props.hasNext()) { Property prop = props.nextProperty(); String name = prop.getName(); //System.out.println("property -- "+name); String value=null; String[] linkFields =null; if (prop.getDefinition().isMultiple() && (name.equalsIgnoreCase("links"))) { StringBuffer buf = new StringBuffer(); //buf.append("Link Type : "); Value[] values = prop.getValues(); for (int i = 0; i < values.length; i++) { buf.append(i > 0 ? "," : ""); buf.append(values[i].getString()); } value = buf.toString(); String[] tokens = value.split(","); for (int i=0;i<tokens.length;i++) { //System.out.println(" tokens "+tokens[i]); linkFields = tokens[i].split("\\\\"); for (int k=0; k<linkFields.length; k++) { //System.out.println(" value of k "+ k + " linkfield" + linkFields[k] ); if (k==0){ %> <b>Link Type:</b> <%= linkFields[k] %>,<% continue;} if (k==1){ %> <b> Link Text: </b><%= linkFields[k] %>,<%continue;} if (k==2){ %> <b>Link URL: </b><%= linkFields[k] %><br /><%continue;} } } } else { if (name.equalsIgnoreCase("links")){ value = prop.getString(); linkFields = value.split("\\\\"); for (int k=0; k<linkFields.length; k++) { //System.out.println(" value of k "+ k + " linkfield" + linkFields[k] ); if (k==0){ %> <b>Link Type:</b> <%= linkFields[k] %>,<% continue;} if (k==1){ %> <b> Link Text: </b><%= linkFields[k] %>,<%continue;} if (k==2){ %> <b>Link URL: </b><%= linkFields[k] %><br /><%continue;} } } } } %> <br> ------------------------------- <br><br> <b>OTHER IMAGES:</b> <br> <% for (Node n1 : JcrUtils.getChildNodes(node)){ String imagePath = n1.getPath().toString(); Resource imageResource = resourceResolver.getResource(imagePath); Node imageNode = imageResource.adaptTo(Node.class); ValueMap imageNodeProps = imageResource.adaptTo(ValueMap.class); String imageName = null; imageName= imageNodeProps.get("fileReference", "None"); %> <br> <b>Image Path :</b> <%= imageName %> <br> <% } } %><br><br> -------------------------------<br> <b>**HERO ENDS**</b><br> ------------------------------- <br>
The final task is to create an AEM site that lets an author drag the hero component onto a page during design time, as shown in the following illustration.

Create a CQ web page that lets you test the Hero component:
- Go to the CQ welcome page at http://[host name]:[port]; for example, http://localhost:4502.
- Select Websites. (If you are using AEM 5.6, click Tools from the menu on the left.)
- From the left hand pane, select Websites.
- Select New Page.
- Specify the title of the page in the Title field.
- Specify the name of the page in the Name field.
- Select templateHook from the template list that appears. This value represents the template that is created in this development article. If you do not see it, then repeat the steps in this development article. For example, if you made a typing mistake when entering in path information, the template will not show up in the New Page dialog box.
- Open the new page that you created by double-clicking it in the right pane. The new page opens in a web browser.
You will see the CQ sidekick and the Hero component under the Hook category. You can drag and drop the Hero component onto the CQ page.
If the CQ sidekick is empty, you can populate it by clicking the Design button located at the bottom of the sidekick. Next click the Edit button that appears and select Hook from the list of categories that appear as shown here.

To view the sidekick with the Hook category, click the down arrow icon that appears on the sidekick.
Drag the Hero component on the AEM web page. Double click on the component and you see the dialog that you created in this development article. You can drag images from the AEM content finder to the component. Click Ok and you will see the values in the AEM web page.
Congratulations, you have just created an advanced AEM component that uses many features such as drag and drop, a rich text editor, and a custom xtype. Please refer to the AEM community page for other articles that discuss how to build AEM component, services, and applications.