Skip to main content

Dialog Fields & Granite UI Reference

Series: AEM Core Development — Part 4

Updated 3 min readMarkdown
Part of seriesAEM Core Development
Dialog Fields & Granite UI Reference

Dialogs are how authors configure components. In AEM, dialogs are built with Granite UI using Coral UI 3 widgets, defined as XML nodes. This post is a practical reference for the fields you'll use most.

Dialog Anatomy

Every dialog follows the same skeleton:

_cq_dialog/.content.xml
└── content (container)
    └── items
        └── tabs / fields

Each field is a node with a sling:resourceType that determines the widget, and a name property that determines where the value is stored (always prefixed with ./ for the component node).

Common Field Types

All resource types below are under granite/ui/components/coral/foundation/form/.

Field Resource type suffix Typical use
Text field textfield Titles, labels
Text area textarea Descriptions
Checkbox checkbox Boolean toggles
Select / dropdown select Fixed option lists
Number numberfield Counts, sizes
Date picker datepicker Dates
Path field pathfield Linking to pages or assets
Rich text cq/gui/components/authoring/dialog/richtext Formatted text
Multifield multifield Repeating groups of fields

Text Field with Validation

<title
    jcr:primaryType="nt:unstructured"
    sling:resourceType="granite/ui/components/coral/foundation/form/textfield"
    fieldLabel="Title"
    fieldDescription="Keep under 60 characters"
    maxlength="60"
    required="{Boolean}true"
    name="./title"/>

Checkbox

Checkboxes need two extra properties to store a proper boolean:

<showSubtitle
    jcr:primaryType="nt:unstructured"
    sling:resourceType="granite/ui/components/coral/foundation/form/checkbox"
    text="Show subtitle"
    name="./showSubtitle"
    value="{Boolean}true"
    uncheckedValue="{Boolean}false"/>
<alignment
    jcr:primaryType="nt:unstructured"
    sling:resourceType="granite/ui/components/coral/foundation/form/select"
    fieldLabel="Alignment"
    name="./alignment">
    <items jcr:primaryType="nt:unstructured">
        <left jcr:primaryType="nt:unstructured" text="Left" value="left"/>
        <center jcr:primaryType="nt:unstructured" text="Center" value="center" selected="{Boolean}true"/>
        <right jcr:primaryType="nt:unstructured" text="Right" value="right"/>
    </items>
</alignment>

Path Field

Use rootPath to restrict what authors can browse:

<link
    jcr:primaryType="nt:unstructured"
    sling:resourceType="granite/ui/components/coral/foundation/form/pathfield"
    fieldLabel="Link"
    rootPath="/content/mysite"
    name="./linkURL"/>

For assets, set rootPath="/content/dam/mysite".

Multifield

Multifields let authors add repeating items. The composite approach stores each item as a child node:

<links
    jcr:primaryType="nt:unstructured"
    sling:resourceType="granite/ui/components/coral/foundation/form/multifield"
    composite="{Boolean}true"
    fieldLabel="Links">
    <field
        jcr:primaryType="nt:unstructured"
        sling:resourceType="granite/ui/components/coral/foundation/container"
        name="./links">
        <items jcr:primaryType="nt:unstructured">
            <label
                jcr:primaryType="nt:unstructured"
                sling:resourceType="granite/ui/components/coral/foundation/form/textfield"
                fieldLabel="Label"
                name="./label"/>
            <url
                jcr:primaryType="nt:unstructured"
                sling:resourceType="granite/ui/components/coral/foundation/form/pathfield"
                fieldLabel="URL"
                name="./url"/>
        </items>
    </field>
</links>

Read it in your model with @ChildResource private List<Resource> links; or map it to a small model class.

Organizing with Tabs

<content
    jcr:primaryType="nt:unstructured"
    sling:resourceType="granite/ui/components/coral/foundation/tabs">
    <items jcr:primaryType="nt:unstructured">
        <properties
            jcr:primaryType="nt:unstructured"
            jcr:title="Properties"
            sling:resourceType="granite/ui/components/coral/foundation/container">
            <items jcr:primaryType="nt:unstructured">
                <!-- fields here -->
            </items>
        </properties>
    </items>
</content>

Tips

  • Use the Touch UI dialog only; classic UI dialogs are legacy
  • Look at Core Components dialogs in /libs/core/wcm/components for reliable patterns to copy
  • Use granite:hide / show-hide behavior via granite:class and clientlibs for conditional fields
  • Inspect a dialog in CRXDE Lite (/apps/.../_cq_dialog) to learn how existing ones are structured

What's Next

Dialogs and models are now connected, but things don't always work on the first try. Next up: why Sling Model injection fails and how to fix it.


Next in this series: [Fixing Common Sling Model Injection Issues]

About the author

  • AEM Technical Lead experienced with building and architecting solutions on AEM Sites and Assets. Sharing practical tutorials, real-world implementation lessons, and best practices to help fellow developers and leads navigate AEM.

Which Granite UI field gave you the most trouble? Multifields and showing or hiding fields are the usual suspects. Tell me what you're stuck on and I may turn it into a follow-up post.

AEM Core Development

Part 4 of 6

"Hands-on component building, Sling Models, HTL, and dialog configuration — the everyday toolkit every AEM developer needs."

Up nextFixing Common Sling Model Injection IssuesSeries: AEM Core Development — Part 5