Building an AEM Authoring Component out of HTL/Sightly; no JSP required!

Benjamin Solum
5 min readMay 2, 2021
Visual hierarchy of Coral Foundation components

Adobe gives us a ton of authoring components out of the box!

I mean, just look at them all in CRXDE 😲!

If you’ve spent any time on an AEM project you’ve no doubt composed component authoring dialogs using: Textfields, Switches, Multifields, etc. Adobe does a great job of providing almost everything a developer could need!

Occasionally though, we’ll need something a little more custom and on those occasions, datasource takes care of me 95% of the time.

For example, let’s say we have a Button/CTA component that needs to open up a modal/dialog. We can easily build a list of modal components on the page using a servlet and then provide that list via datasource:

<modalid
jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/coral/foundation/form/select"
fieldDescription="When clicked open Modal with corresponding id."
fieldLabel="Modal ID"
name="./modalId">
<datasource
jcr:primaryType="nt:unstructured"
sling:resourceType="apps/mysite/datasource/modalsOnPage"/></modalid>

Straightforward and easy for a Content Author to use, right?

This article is for us 5%’ers who need something truly custom!

In my case, I have an SVG Sprite that contains all of the site’s iconography. If you aren’t using SVG Sprites (or aren’t familiar with the term), CSS Tricks is a great place to start but the gist is that you should probably be using SVG sprites over icon fonts.

Anyway, I needed a list of links where I could assign an icon to each link (if the author wanted). I didn’t want to display all icons, just ones appropriate for links. They also needed titles, just to help describe what the icon represented. The UI didn’t need to be anything special and I wanted it to fit with the CoralUI aesthetic so using a Coral.Select makes sense here.

Ultimately, this is what the end product looked like:

List of icons in an authoring dialog
A Coral.Select with my filtered list of icons!

But before I could get there, I needed to figure out how to build authoring components. After some Google searching (and almost always ending up on the terse AEM docs or support forms) I gave up and decided to jump into the JCR and just look at how the text field works.

JCR for the textfield component
JCR view of the textfield

A render.jsp huh? Weird. So I looked for other, newer components. Same thing. Every authoring component was composed of a JSP. Even though HTL is the “preferred and recommended server-side template system for HTML in AEM”, all authoring components are built with JSP.

Why? Can we not use HTL to build authoring components? I scoured the internet for answers, but came up empty until I noticed a note on the Creating a New Granite UI Field Component doc page:

Note: At the moment, JSP is the preferred scripting method, as passing information from one component to another (which is quite frequent in the context of form/fields) is not easily achieved in HTL.

So I created an HTL component and tried it out! I looked at some other examples and quickly threw together an empty Coral.Select in the HTL…

Code for the select

… and I found out the docs were right! I had no easy way to get the value supplied from a content author. The properties object referenced the attributes on my XML tag:

XML declaration for icon component

So, I could create the entire UI for the component, but there was no way for me retrieve the saved JCR value supplied by a content author. Every time a content author opened the dialog, the component would act as if it had never saved. Obviously this was not a tenable solution.

So, I referred back to the docs (and looked at a few more JCR components for good measure) and found that this is the “magic” that JSP uses to pull in the JCR value for an authoring component:

// Delivers the value of the field (read from the content) ValueMap vm = (ValueMap) request.getAttribute(Field.class.getName()); vm.get(“value, String.class”);

So, theoretically all we need to do is gain access to that Field.class attribute on the request and then provide our components name (properties.name). So I attached a Sling model and used the debugger to peer inside the request attributes looking a “Field.class” to see if I could find my missing JCR data.

No dice. I was about ready to give up and submit to my JSP overlords when I reached out to my brother Tim Solum, who is a much stronger Java developer than I am (I’m supposed to be the Front-End AEM guy after all). After some additional poking around with Tim, we found my missing JCR data under FormData.class.

How/why did it change between the JSP and Sling Model? I have no idea. I chalk it up to AEM magic but if you have a better answer sound off in the comments 😊!

The resulting Sling model boiled down to a single reusable method that would grab all values for a given authoring dialog request:

public ValueMap getValues() { Stack<FormData> formData = (Stack<FormData>) request.getAttribute(FormData.class.getName()); return formData.peek().getValueMap(); }

From there, we could easily grab values for a given field like so:

data-sly-use.dialogvalues="SITE.models.DialogValues"
value="${dialogvalues.values[properties.name]}"

So that’s basically it! The rest of the icons I pulled in with Ajax and some JavaScript doc parsing (told you I was the Front-End). If you prefer, you could definitely parse the SVG Sprite within the Sling Model and return a Title/Sprite breakdown that way but we have HMR supported builds and I didn’t want to have to rebuild the Front-End and toss the Sprite in the JCR in order for new icons to show.

I’ll update this article later with a few Github gists showing off all the source files so you too can be the proud owner of a custom, filterable icon select component!

Update: Here’s the Gist.

If anything is unclear, let me know below and I’ll try to clear it up. Otherwise, thanks for reading!

--

--

Benjamin Solum

Christian, husband, father, web developer, gamer, scuba diver, @Vikings fan, and aquatic biology enthusiast. Soli Deo gloria!