Component Dialogs
Dialogs are the authoring interface for components. When an author double-clicks a component on a page, a dialog opens with form fields for configuring it. Every value the author enters is stored as a JCR property on the component's content node.
Dialog structure
All Touch UI dialogs follow the same nested XML structure. Here is the skeleton:
<?xml version="1.0" encoding="UTF-8"?>
<jcr:root 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"
xmlns:granite="http://www.adobe.com/jcr/granite/1.0"
xmlns:sling="http://sling.apache.org/jcr/sling/1.0"
jcr:primaryType="nt:unstructured"
jcr:title="Component Name"
sling:resourceType="cq/gui/components/authoring/dialog">
<content jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/container">
<items jcr:primaryType="nt:unstructured">
<!-- Tabs or fields go here -->
</items>
</content>
</jcr:root>
The dialog lives in _cq_dialog/.content.xml inside the component folder.
Common field types
Textfield -- single-line text
<title jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/form/textfield"
fieldLabel="Title"
fieldDescription="Enter the component title"
name="./title"
required="{Boolean}true"
maxlength="100"/>
Textarea -- multi-line text
<description jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/form/textarea"
fieldLabel="Description"
name="./description"
rows="5"/>
Rich Text Editor (RTE)
<richText jcr:primaryType="nt:unstructured"
sling:resourceType="cq/gui/components/authoring/dialog/richtext"
fieldLabel="Body Text"
name="./text"
useFixedInlineToolbar="{Boolean}true"/>
Number field
<count jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/form/numberfield"
fieldLabel="Item Count"
name="./count"
min="{Long}1"
max="{Long}100"
step="{Long}1"
value="{Long}10"/>
Checkbox
<featured jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/form/checkbox"
text="Featured"
name="./featured"
value="{Boolean}true"
uncheckedValue="{Boolean}false"/>
Select (dropdown)
<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" selected="{Boolean}true"/>
<center jcr:primaryType="nt:unstructured"
text="Center" value="center"/>
<right jcr:primaryType="nt:unstructured"
text="Right" value="right"/>
</items>
</alignment>
Path browser -- select a page or asset
<link jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/form/pathfield"
fieldLabel="Link"
fieldDescription="Select a page"
name="./linkPath"
rootPath="/content"
filter="hierarchyNotFile"/>
filter value | Shows |
|---|---|
hierarchyNotFile | Pages only (no assets) |
nosystem | Hides system paths |
| (none) | Shows everything |
Image upload (file upload)
<image jcr:primaryType="nt:unstructured"
sling:resourceType="cq/gui/components/authoring/dialog/fileupload"
fieldLabel="Image"
name="./file"
fileNameParameter="./fileName"
fileReferenceParameter="./fileReference"
allowUpload="{Boolean}true"
mimeTypes="[image/gif,image/jpeg,image/png,image/svg+xml,image/webp]"/>
Hidden field
<type jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/form/hidden"
name="./sling:resourceType"
value="mysite/components/hero"/>
Date picker
<eventDate jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/form/datepicker"
fieldLabel="Event Date"
name="./eventDate"
type="date"
displayedFormat="YYYY-MM-DD"/>
Color picker
<bgColor jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/form/colorfield"
fieldLabel="Background Color"
name="./backgroundColor"
value="#ffffff"/>
Tabs
Most components group fields into tabs:
<tabs jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/tabs"
maximized="{Boolean}true">
<items jcr:primaryType="nt:unstructured">
<content jcr:primaryType="nt:unstructured"
jcr:title="Content"
sling:resourceType="granite/ui/components/coral/foundation/container"
margin="{Boolean}true">
<items jcr:primaryType="nt:unstructured">
<!-- Content fields -->
</items>
</content>
<style jcr:primaryType="nt:unstructured"
jcr:title="Style"
sling:resourceType="granite/ui/components/coral/foundation/container"
margin="{Boolean}true">
<items jcr:primaryType="nt:unstructured">
<!-- Style fields -->
</items>
</style>
</items>
</tabs>
A common tab pattern:
| Tab | Fields |
|---|---|
| Content | Title, text, image -- the main content |
| Style | Alignment, color, size -- visual configuration |
| Advanced | ID, CSS class, accessibility -- technical settings |
Multifield -- repeatable field groups
Multifields let authors add multiple items of the same structure:
<links jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/form/multifield"
fieldLabel="Links"
composite="{Boolean}true">
<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"
required="{Boolean}true"/>
<url jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/form/pathfield"
fieldLabel="URL"
name="./url"
rootPath="/content"/>
<openInNewTab jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/form/checkbox"
text="Open in new tab"
name="./openInNewTab"
value="{Boolean}true"/>
</items>
</field>
</links>
Setting composite="{Boolean}true" stores each item as a child node with sub-properties:
component-node/
└── links/
├── item0/
│ ├── label = "Home"
│ ├── url = "/content/mysite/en"
│ └── openInNewTab = false
└── item1/
├── label = "Blog"
├── url = "/content/mysite/en/blog"
└── openInNewTab = false
In your Sling Model, use @ChildResource to read multifield items (covered in the next chapter).
The name attribute
The name attribute on each field controls where the value is stored in the JCR:
| Name value | Stored at |
|---|---|
./title | title property on the component node |
./jcr:title | jcr:title property (standard JCR property) |
./links/item0/label | Nested under links/item0 child node |
The ./ prefix means "relative to the current resource" (the component's content node).
Practical example -- Hero component dialog
A complete dialog for a Hero banner component:
<?xml version="1.0" encoding="UTF-8"?>
<jcr:root 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"
xmlns:granite="http://www.adobe.com/jcr/granite/1.0"
xmlns:sling="http://sling.apache.org/jcr/sling/1.0"
jcr:primaryType="nt:unstructured"
jcr:title="Hero"
sling:resourceType="cq/gui/components/authoring/dialog">
<content jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/container">
<items jcr:primaryType="nt:unstructured">
<tabs jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/tabs"
maximized="{Boolean}true">
<items jcr:primaryType="nt:unstructured">
<!-- Content Tab -->
<content jcr:primaryType="nt:unstructured"
jcr:title="Content"
sling:resourceType="granite/ui/components/coral/foundation/container"
margin="{Boolean}true">
<items jcr:primaryType="nt:unstructured">
<columns jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/fixedcolumns"
margin="{Boolean}true">
<items jcr:primaryType="nt:unstructured">
<column jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/container">
<items jcr:primaryType="nt:unstructured">
<heading jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/form/textfield"
fieldLabel="Heading"
name="./heading"
required="{Boolean}true"/>
<subheading jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/form/textarea"
fieldLabel="Subheading"
name="./subheading"
rows="3"/>
<image jcr:primaryType="nt:unstructured"
sling:resourceType="cq/gui/components/authoring/dialog/fileupload"
fieldLabel="Background Image"
name="./file"
fileReferenceParameter="./fileReference"
mimeTypes="[image/jpeg,image/png,image/webp]"/>
<ctaLabel jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/form/textfield"
fieldLabel="CTA Label"
name="./ctaLabel"/>
<ctaLink jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/form/pathfield"
fieldLabel="CTA Link"
name="./ctaLink"
rootPath="/content"/>
</items>
</column>
</items>
</columns>
</items>
</content>
<!-- Style Tab -->
<style jcr:primaryType="nt:unstructured"
jcr:title="Style"
sling:resourceType="granite/ui/components/coral/foundation/container"
margin="{Boolean}true">
<items jcr:primaryType="nt:unstructured">
<columns jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/fixedcolumns"
margin="{Boolean}true">
<items jcr:primaryType="nt:unstructured">
<column jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/container">
<items jcr:primaryType="nt:unstructured">
<overlay jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/form/select"
fieldLabel="Overlay"
name="./overlay">
<items jcr:primaryType="nt:unstructured">
<none jcr:primaryType="nt:unstructured"
text="None" value="none"/>
<light jcr:primaryType="nt:unstructured"
text="Light" value="light"/>
<dark jcr:primaryType="nt:unstructured"
text="Dark" value="dark" selected="{Boolean}true"/>
</items>
</overlay>
<fullWidth jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/form/checkbox"
text="Full Width"
name="./fullWidth"
value="{Boolean}true"/>
</items>
</column>
</items>
</columns>
</items>
</style>
</items>
</tabs>
</items>
</content>
</jcr:root>
For more dialog patterns and the full Granite UI component reference, see the Touch UI Component Dialogs reference. See also Coral UI for the underlying design system and Custom Dialog Widgets for building your own field types.
Conditional field visibility (show/hide)
A common requirement is showing or hiding fields based on the value of another field. Granite UI supports this with the
granite:class and showhide target pattern. For example, show a "Link URL" field only when the author selects "Custom
Link" from a dropdown:
<!-- The controlling field: a select dropdown -->
<linkType jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/form/select"
fieldLabel="Link Type"
name="./linkType"
granite:class="cq-dialog-dropdown-showhide">
<granite:data jcr:primaryType="nt:unstructured"
cq-dialog-dropdown-showhide-target=".link-type-showhide-target"/>
<items jcr:primaryType="nt:unstructured">
<none jcr:primaryType="nt:unstructured"
text="None" value="none"/>
<page jcr:primaryType="nt:unstructured"
text="Page Link" value="page"/>
<custom jcr:primaryType="nt:unstructured"
text="Custom URL" value="custom"/>
</items>
</linkType>
<!-- Shown only when linkType = "page" -->
<pagePath jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/form/pathfield"
fieldLabel="Page"
name="./pagePath"
rootPath="/content"
granite:class="hide link-type-showhide-target">
<granite:data jcr:primaryType="nt:unstructured"
showhidetargetvalue="page"/>
</pagePath>
<!-- Shown only when linkType = "custom" -->
<customUrl jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/form/textfield"
fieldLabel="Custom URL"
name="./customUrl"
granite:class="hide link-type-showhide-target">
<granite:data jcr:primaryType="nt:unstructured"
showhidetargetvalue="custom"/>
</customUrl>
How it works:
- The controlling field has
granite:class="cq-dialog-dropdown-showhide"and agranite:datachild that specifies the CSS target class viacq-dialog-dropdown-showhide-target - Each conditional field has
granite:class="hide <target-class>"(hidden by default) and agranite:datachild withshowhidetargetvaluematching the dropdown value that should reveal it - AEM's built-in
cq-dialog-dropdown-showhideclient library handles the show/hide logic automatically
Hiding inherited dialog fields
When your proxy component extends a Core Component and you want to remove a field from the inherited dialog, use
granite:hide:
<!-- In your proxy component's _cq_dialog/.content.xml, target the inherited field by node name -->
<subtitle jcr:primaryType="nt:unstructured"
granite:hide="{Boolean}true"/>
This hides the subtitle field without needing to rewrite the entire dialog. The field must be referenced by the same
node name used in the parent dialog.
Summary
You learned:
- Dialog structure -- the nested XML hierarchy of containers, tabs, and fields
- Common field types: textfield, textarea, RTE, numberfield, checkbox, select, pathfield, file upload, datepicker, colorfield, hidden
- Tabs for organizing fields into logical groups
- Multifield for repeatable field groups
- The
nameattribute and how it maps to JCR properties - A complete Hero component dialog example
- Conditional visibility with the dropdown show/hide pattern
granite:hidefor removing inherited dialog fields in proxy components
Next up: Sling Models -- injecting content into Java models, common annotations, adapters, exporters, and best practices.