AEM Dialog Components #3: Checkbox - Boolean Selection

AEM Dialog Components #3: Checkbox

What is a Checkbox?

The Checkbox is a Granite UI component that allows authors to enable or disable an option (boolean value: true/false).

Common use cases:

  • Show/hide elements
  • Enable/disable features
  • Open links in new tab
  • Newsletter opt-in
  • Configuration flags

Basic Configuration

Minimal XML Dialog

<showTitle
    jcr:primaryType="nt:unstructured"
    sling:resourceType="granite/ui/components/coral/foundation/form/checkbox"
    name="./showTitle"
    text="Show Title"
    value="{Boolean}true"/>

Essential properties:

  • sling:resourceType - Always granite/ui/components/coral/foundation/form/checkbox
  • name - JCR path (always use ./)
  • text - Visible label next to the checkbox
  • value - Value when checked (default: {Boolean}true)

Main Properties

1. Checked (Selected by Default)

<enabled
    jcr:primaryType="nt:unstructured"
    sling:resourceType="granite/ui/components/coral/foundation/form/checkbox"
    name="./enabled"
    text="Enable Feature"
    checked="{Boolean}true"
    value="{Boolean}true"/>

When to use: Features enabled by default that the user can disable.


2. Value and uncheckedValue

<openInNewTab
    jcr:primaryType="nt:unstructured"
    sling:resourceType="granite/ui/components/coral/foundation/form/checkbox"
    name="./openInNewTab"
    text="Open in new tab"
    value="{Boolean}true"
    uncheckedValue="{Boolean}false"/>

Important:

  • value - Value saved when checked (default: true)
  • uncheckedValue - Value saved when unchecked (default: saves nothing)

Best practice: Always set uncheckedValue="{Boolean}false" to explicitly save false!


3. Disabled

<readOnlyFlag
    jcr:primaryType="nt:unstructured"
    sling:resourceType="granite/ui/components/coral/foundation/form/checkbox"
    name="./readOnlyFlag"
    text="Read Only (System Managed)"
    checked="{Boolean}true"
    disabled="{Boolean}true"
    value="{Boolean}true"/>

Practical Examples

Example 1: Show/Hide Title

<showTitle
    jcr:primaryType="nt:unstructured"
    sling:resourceType="granite/ui/components/coral/foundation/form/checkbox"
    fieldLabel="Title Visibility"
    fieldDescription="Control title display"
    name="./showTitle"
    text="Show component title"
    value="{Boolean}true"
    uncheckedValue="{Boolean}false"/>

HTL:

<h2 data-sly-test="${properties.showTitle}">
  ${properties.title}
</h2>

Example 2: Link in New Tab

<newTab
    jcr:primaryType="nt:unstructured"
    sling:resourceType="granite/ui/components/coral/foundation/form/checkbox"
    name="./newTab"
    text="Open link in new tab"
    value="{Boolean}true"
    uncheckedValue="{Boolean}false"/>

HTL:

<a href="${properties.url}"
   data-sly-attribute.target="${properties.newTab ? '_blank' : ''}"
   data-sly-attribute.rel="${properties.newTab ? 'noopener noreferrer' : ''}">
  ${properties.linkText}
</a>

Example 3: Enable Animations

<enableAnimations
    jcr:primaryType="nt:unstructured"
    sling:resourceType="granite/ui/components/coral/foundation/form/checkbox"
    fieldLabel="Animations"
    name="./enableAnimations"
    text="Enable animations"
    checked="{Boolean}true"
    value="{Boolean}true"
    uncheckedValue="{Boolean}false"/>

HTL:

<div class="component${properties.enableAnimations ? ' animated' : ''}">
  <!-- Content -->
</div>

Example 4: Featured Content

<isFeatured
    jcr:primaryType="nt:unstructured"
    sling:resourceType="granite/ui/components/coral/foundation/form/checkbox"
    fieldLabel="Featured"
    fieldDescription="Mark this content as featured"
    name="./isFeatured"
    text="Feature this content"
    value="{Boolean}true"
    uncheckedValue="{Boolean}false"/>

Usage: "Featured" badge in frontend, priority sorting.


Complete Dialog with Checkboxes

<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0"
    xmlns:granite="http://www.adobe.com/jcr/granite/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="Link Component"
    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">
                <items jcr:primaryType="nt:unstructured">

                    <content
                        jcr:primaryType="nt:unstructured"
                        jcr:title="Content"
                        sling:resourceType="granite/ui/components/coral/foundation/container">
                        <items jcr:primaryType="nt:unstructured">

                            <!-- Link Text -->
                            <linkText
                                jcr:primaryType="nt:unstructured"
                                sling:resourceType="granite/ui/components/coral/foundation/form/textfield"
                                fieldLabel="Link Text"
                                name="./linkText"
                                required="{Boolean}true"/>

                            <!-- URL -->
                            <url
                                jcr:primaryType="nt:unstructured"
                                sling:resourceType="granite/ui/components/coral/foundation/form/pathfield"
                                fieldLabel="URL"
                                name="./url"
                                required="{Boolean}true"
                                rootPath="/content"/>

                            <!-- Open in new tab -->
                            <newTab
                                jcr:primaryType="nt:unstructured"
                                sling:resourceType="granite/ui/components/coral/foundation/form/checkbox"
                                name="./newTab"
                                text="Open in new tab"
                                value="{Boolean}true"
                                uncheckedValue="{Boolean}false"/>

                            <!-- Show icon -->
                            <showIcon
                                jcr:primaryType="nt:unstructured"
                                sling:resourceType="granite/ui/components/coral/foundation/form/checkbox"
                                name="./showIcon"
                                text="Show link icon"
                                checked="{Boolean}true"
                                value="{Boolean}true"
                                uncheckedValue="{Boolean}false"/>

                        </items>
                    </content>

                </items>
            </tabs>
        </items>
    </content>
</jcr:root>

Usage in HTL

Simple Boolean Reading

<!-- Show element if checked -->
<div data-sly-test="${properties.showTitle}">
  <h2>${properties.title}</h2>
</div>

<!-- Add CSS class if checked -->
<div class="component${properties.enableAnimations ? ' animated' : ''}">
  Content
</div>

<!-- Conditional attribute -->
<a href="${properties.url}"
   data-sly-attribute.target="${properties.newTab ? '_blank' : ''}">
  Link
</a>

With Sling Model

@Model(adaptables = Resource.class)
public class LinkModel {

    @ValueMapValue
    private String linkText;

    @ValueMapValue
    private String url;

    @ValueMapValue(name = "newTab")
    private boolean openInNewTab;

    @ValueMapValue(name = "showIcon")
    private boolean showIcon;

    public String getLinkText() {
        return linkText;
    }

    public String getUrl() {
        return url;
    }

    public boolean isOpenInNewTab() {
        return openInNewTab;
    }

    public String getTarget() {
        return openInNewTab ? "_blank" : null;
    }

    public String getRel() {
        return openInNewTab ? "noopener noreferrer" : null;
    }

    public boolean isShowIcon() {
        return showIcon;
    }

    public String getLinkClasses() {
        return showIcon ? "link link-with-icon" : "link";
    }
}

HTL with Model:

<a data-sly-use.model="com.mysite.models.LinkModel"
   href="${model.url}"
   class="${model.linkClasses}"
   data-sly-attribute.target="${model.target}"
   data-sly-attribute.rel="${model.rel}">
  ${model.linkText}
  <span data-sly-test="${model.showIcon}" class="icon"></span>
</a>

Custom Values

Example: Strings Instead of Boolean

<alignment
    jcr:primaryType="nt:unstructured"
    sling:resourceType="granite/ui/components/coral/foundation/form/checkbox"
    name="./centerAlign"
    text="Center align content"
    value="center"
    uncheckedValue="left"/>

JCR Result:

  • Checked → centerAlign = "center"
  • Unchecked → centerAlign = "left"

HTL:

<div class="content align-${properties.centerAlign || 'left'}">
  Content
</div>

Checkbox vs Select vs Radio

Component Use Values
Checkbox Single On/Off Boolean (true/false)
Radio Choose 1 from N options String (selected value)
Select Choose 1 from many options String (selected value)

Use Checkbox when: You have a single option to enable/disable.


Common Issues

❌ Issue 1: Value not saved when unchecked

<!-- WRONG - unchecked doesn't save anything in JCR -->
<enabled
    name="./enabled"
    text="Enable"
    value="{Boolean}true"/>

<!-- CORRECT - explicitly saves false -->
<enabled
    name="./enabled"
    text="Enable"
    value="{Boolean}true"
    uncheckedValue="{Boolean}false"/>

Symptom: In HTL ${properties.enabled} is null instead of false.

Solution: Always add uncheckedValue="{Boolean}false".


❌ Issue 2: Boolean without type hint

<!-- WRONG -->
<enabled
    value="true"
    uncheckedValue="false"/>

<!-- CORRECT -->
<enabled
    value="{Boolean}true"
    uncheckedValue="{Boolean}false"/>

❌ Issue 3: Checked doesn't work

<!-- WRONG - checked as string -->
<enabled
    checked="true"/>

<!-- CORRECT -->
<enabled
    checked="{Boolean}true"/>

❌ Issue 4: Wrong HTL test

<!-- RISKY - null is falsy -->
<div data-sly-test="${properties.enabled}">
  <!-- Doesn't appear if enabled is not set -->
</div>

<!-- BETTER - explicit comparison -->
<div data-sly-test="${properties.enabled == true}">
  <!-- Appears only if explicitly true -->
</div>

<!-- OR fallback in model -->
public boolean isEnabled() {
    return enabled != null ? enabled : false;
}

Best Practices

  1. Always uncheckedValue: uncheckedValue="{Boolean}false"
  2. Type hints for boolean: value="{Boolean}true"
  3. Descriptive text: "Show title" not just "Title"
  4. fieldDescription: Explain the effect of the checkbox
  5. Useful defaults: checked="{Boolean}true" for features enabled by default
  6. Clear naming: showTitle, enableFeature, isActive
  7. Validation in Model: Handle null → false
  8. Conditional attributes: Use ternary operator in HTL

Advanced Patterns

1. Checkbox with Show/Hide

<showAdvanced
    jcr:primaryType="nt:unstructured"
    sling:resourceType="granite/ui/components/coral/foundation/form/checkbox"
    name="./showAdvanced"
    text="Show advanced options"
    value="{Boolean}true"
    uncheckedValue="{Boolean}false"/>

<advancedOptions
    jcr:primaryType="nt:unstructured"
    sling:resourceType="granite/ui/components/coral/foundation/container"
    granite:hide="${!properties.showAdvanced}">
    <items jcr:primaryType="nt:unstructured">
        <!-- Advanced fields here -->
    </items>
</advancedOptions>

Show/hide fields based on checkbox.


2. Multiple Related Checkboxes

<enableFeatureA
    name="./enableFeatureA"
    text="Enable Feature A"
    value="{Boolean}true"
    uncheckedValue="{Boolean}false"/>

<enableFeatureB
    name="./enableFeatureB"
    text="Enable Feature B"
    value="{Boolean}true"
    uncheckedValue="{Boolean}false"/>

<enableFeatureC
    name="./enableFeatureC"
    text="Enable Feature C"
    value="{Boolean}true"
    uncheckedValue="{Boolean}false"/>

HTL: Combine with OR logic

<div data-sly-test="${properties.enableFeatureA || properties.enableFeatureB || properties.enableFeatureC}">
  At least one feature is enabled
</div>

Next Lesson

In the next lesson we'll see the Select component for dropdowns with predefined options.

Resources:


Guide #3 of the AEM Dialog Components series - ← Previous lesson | Next lesson →