Skip to content

Coral UI trong AEM 6.5

Giới thiệu

Coral UI là thư viện web components chính thức của Adobe, cung cấp toàn bộ giao diện Touch UI của AEM 6.5 - bao gồm dialogs, Sites console, DAM console, thanh công cụ page editor và tất cả các admin interface. Khi bạn xây dựng custom dialog fields, admin consoles, hoặc author-facing UI trong AEM 6.5, bạn sẽ sử dụng các components của Coral UI.

Coral UI 3 (phiên bản được sử dụng trong AEM 6.5) được xây dựng dựa trên chuẩn Web Components (Custom Elements v1). Các components được sử dụng như các HTML elements với thuộc tính is="coral-*" hoặc như các tags độc lập như <coral-dialog>.

Granite UI (Server-side) → renders HTML với Coral classes và attributes
Coral UI 3 (Client-side) → Cung cấp interactive web components

Granite UI vs Coral UI

Hai khái niệm này thường bị nhầm lẫn. Chúng làm việc cùng nhau nhưng ở các lớp khác nhau:

LayerFrameworkNơi chạyChức năng
Granite UIServer-side (Sling)AEM serverĐọc dialog XML, render HTML markup với Coral classes và attributes
Coral UI 3Client-side (JS/CSS)BrowserCung cấp interactive web components (buttons, dialogs, selects, etc.)

Khi bạn viết dialog XML như sling:resourceType="granite/ui/components/coral/foundation/form/textfield", Granite UI sẽ render server-side HTML, và Coral UI's JavaScript sẽ enhance nó thành một text field tương tác trong browser.

💡 Mẹo: Bạn tương tác với Granite UI khi viết dialog XML (server-side). Bạn tương tác với Coral UI khi viết client-side JavaScript cho dialog customization, custom fields, hoặc admin pages.


Thư viện Components

AEM 6.5 đi kèm với Coral UI 3. Full API có thể truy cập trên local instance của bạn:

ResourceURL
Coral UI component exampleshttp://localhost:4502/libs/granite/ui/components/coral/foundation/form/field.html
Coral UI 3 API docshttp://localhost:4502/libs/granite/ui/references/coral-ui/coralui3/
Granite UI server-side docshttp://localhost:4502/libs/granite/ui/content/dumplibs.html

Các Coral UI Components thường dùng

ComponentHTMLMục đích
coral-button<button is="coral-button">Buttons với icons và variants
coral-textfield<input is="coral-textfield">Text input fields
coral-textarea<textarea is="coral-textarea">Multi-line text input
coral-select<coral-select>Dropdown select
coral-checkbox<coral-checkbox>Checkbox toggle
coral-radio<coral-radio>Radio button
coral-switch<coral-switch>Toggle switch
coral-dialog<coral-dialog>Modal dialog
coral-alert<coral-alert>Alert / notification banner
coral-table<coral-table>Data table
coral-tabs<coral-tablist> + <coral-panelstack>Tabbed interface
coral-accordion<coral-accordion>Collapsible sections
coral-tag<coral-tag>Tag / chip
coral-tooltip<coral-tooltip>Tooltip on hover
coral-popover<coral-popover>Popover content
coral-progress<coral-progress>Progress bar
coral-wait<coral-wait>Loading spinner
coral-icon<coral-icon>Icon (từ Coral icon set)
coral-masonry<coral-masonry>Masonry grid layout (card view)
coral-columnview<coral-columnview>Column / Miller columns view
coral-shell<coral-shell>AEM shell (global navigation)

Setup và Integration

Để sử dụng Coral UI components trong custom page hoặc template (outside of standard dialogs), load Coral UI libraries qua clientlib dependency.

1. Tạo clientlib với Coral dependencies

File: ui.apps/.../clientlibs/clientlib-coral-custom/.content.xml

xml
<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:cq="http://www.day.com/jcr/cq/1.0"
    jcr:primaryType="cq:ClientLibraryFolder"
    allowProxy="{Boolean}true"
    dependencies="[coralui3,granite.ui.coral.foundation]"
    categories="[myproject.coral-custom]"/>
DependencyCung cấp
coralui3Core Coral UI 3 library (tất cả components, JS, CSS)
granite.ui.coral.foundationGranite UI foundation components (form fields, containers)
granite.ui.shellAEM shell framework (chỉ cần nếu building full admin pages)

2. Load clientlib trong HTL template

File: body.html

html
<sly data-sly-use.clientlib="/libs/granite/sightly/templates/clientlib.html">
    <sly data-sly-call="${clientlib.all @ categories='myproject.coral-custom'}"/>
</sly>

<div class="myproject-custom-ui">
    <button is="coral-button" variant="primary" icon="add">Thêm Item</button>
</div>

Thuộc tính dependencies trong clientlib XML đảm bảo Coral UI 3 được load trước khi custom code của bạn chạy.


Sử dụng Coral UI Components

Buttons

html
<!-- Primary action button -->
<button is="coral-button" variant="primary" icon="check">Lưu</button>

<!-- Secondary / quiet button -->
<button is="coral-button" variant="quiet" icon="edit">Sửa</button>

<!-- Warning button -->
<button is="coral-button" variant="warning" icon="delete">Xóa</button>

<!-- Button với chỉ icon (không label) -->
<button is="coral-button" variant="quietaction" icon="more" iconsize="S"
        title="Thêm tùy chọn"></button>

<!-- Disabled button -->
<button is="coral-button" variant="primary" disabled>Không khả dụng</button>

<!-- Button sizes -->
<button is="coral-button" variant="primary" size="M">Medium</button>
<button is="coral-button" variant="primary" size="L">Large</button>

Button variants: default, primary, secondary, warning, quiet, minimal, quietaction, action

Alerts

html
<!-- Info alert -->
<coral-alert variant="info">
    <coral-alert-header>Thông tin</coral-alert-header>
    <coral-alert-content>Component này có changes chưa được lưu.</coral-alert-content>
</coral-alert>

<!-- Success alert -->
<coral-alert variant="success">
    <coral-alert-header>Đã lưu</coral-alert-header>
    <coral-alert-content>Các thay đổi đã được lưu thành công.</coral-alert-content>
</coral-alert>

<!-- Warning alert -->
<coral-alert variant="warning">
    <coral-alert-header>Cảnh báo</coral-alert-header>
    <coral-alert-content>Hành động này không thể hoàn tác.</coral-alert-content>
</coral-alert>

<!-- Error alert -->
<coral-alert variant="error">
    <coral-alert-header>Lỗi</coral-alert-header>
    <coral-alert-content>Không thể lưu. Vui lòng thử lại.</coral-alert-content>
</coral-alert>

Alert variants: info, success, warning, error, help

Dialogs

html
<!-- Define a dialog -->
<coral-dialog id="myDialog" variant="default">
    <coral-dialog-header>Xác nhận hành động</coral-dialog-header>
    <coral-dialog-content>
        <p>Bạn có chắc chắn muốn xóa item này?</p>
    </coral-dialog-content>
    <coral-dialog-footer>
        <button is="coral-button" variant="default" coral-close>Hủy</button>
        <button is="coral-button" variant="primary" id="confirmBtn">Xóa</button>
    </coral-dialog-footer>
</coral-dialog>

Mở và xử lý dialogs:

javascript
// Mở dialog
var dialog = document.getElementById('myDialog');
dialog.show();

// Xử lý confirm button
document.getElementById('confirmBtn').addEventListener('click', function() {
    // Thực hiện hành động
    dialog.hide();
});

// Lắng nghe dialog close
dialog.on('coral-overlay:close', function() {
    console.log('Dialog đã đóng');
});

Dialog variants: default, error, warning, success, help, info

Select / Dropdown

html
<coral-select name="category" placeholder="Chọn một danh mục">
    <coral-select-item value="news">Tin tức</coral-select-item>
    <coral-select-item value="blog">Blog</coral-select-item>
    <coral-select-item value="product" selected>Sản phẩm</coral-select-item>
    <coral-select-item value="event">Sự kiện</coral-select-item>
</coral-select>

Đọc giá trị được chọn:

javascript
var select = document.querySelector('coral-select[name="category"]');
select.on('change', function() {
    console.log('Đã chọn:', select.value);
});

Tables

html
<coral-table selectable>
    <coral-table-head>
        <coral-table-row>
            <coral-table-headercell>Tên</coral-table-headercell>
            <coral-table-headercell>Trạng thái</coral-table-headercell>
            <coral-table-headercell>Chỉnh sửa</coral-table-headercell>
        </coral-table-row>
    </coral-table-head>
    <coral-table-body>
        <coral-table-row>
            <coral-table-cell>Trang chủ</coral-table-cell>
            <coral-table-cell><coral-status variant="success">Đã xuất bản</coral-status></coral-table-cell>
            <coral-table-cell>2026-01-15</coral-table-cell>
        </coral-table-row>
        <coral-table-row>
            <coral-table-cell>Giới thiệu</coral-table-cell>
            <coral-table-cell><coral-status variant="warning">Bản nháp</coral-status></coral-table-cell>
            <coral-table-cell>2026-01-20</coral-table-cell>
        </coral-table-row>
    </coral-table-body>
</coral-table>

Tabs

html
<coral-tablist>
    <coral-tab>Chung</coral-tab>
    <coral-tab selected>Nâng cao</coral-tab>
    <coral-tab>Phân quyền</coral-tab>
</coral-tablist>
<coral-panelstack>
    <coral-panel>
        <p>Nội dung cài đặt chung</p>
    </coral-panel>
    <coral-panel selected>
        <p>Nội dung cài đặt nâng cao</p>
    </coral-panel>
    <coral-panel>
        <p>Nội dung cài đặt phân quyền</p>
    </coral-panel>
</coral-panelstack>

Icons

Coral UI bao gồm bộ icon toàn diện. Sử dụng thuộc tính icon trên buttons hoặc element <coral-icon>:

html
<!-- Standalone icon -->
<coral-icon icon="edit" size="S"></coral-icon>
<coral-icon icon="delete" size="M"></coral-icon>
<coral-icon icon="check" size="L"></coral-icon>

<!-- Common icons -->
<coral-icon icon="add"></coral-icon>         <!-- + -->
<coral-icon icon="close"></coral-icon>       <!-- × -->
<coral-icon icon="search"></coral-icon>      <!-- 🔍 -->
<coral-icon icon="settings"></coral-icon>    <!-- ⚙ -->
<coral-icon icon="infoCircle"></coral-icon>  <!-- ℹ -->
<coral-icon icon="alert"></coral-icon>       <!-- ⚠ -->
<coral-icon icon="folder"></coral-icon>
<coral-icon icon="image"></coral-icon>
<coral-icon icon="globe"></coral-icon>
<coral-icon icon="user"></coral-icon>
<coral-icon icon="link"></coral-icon>
<coral-icon icon="code"></coral-icon>

Xem tất cả icons tại: http://localhost:4502/libs/granite/ui/references/coral-ui/coralui3/Coral.Icon.html


Coral UI trong Dialog Clientlibs

Trường hợp sử dụng phổ biến nhất của Coral UI trong custom code là dialog clientlibs - JavaScript chạy bên trong component dialogs để thêm custom behaviour (show/hide fields, validation, dynamic defaults).

Show/hide fields dựa trên giá trị dropdown

File: ui.apps/.../clientlibs/clientlib-dialog/js/showhide.js

javascript
(function($, Coral) {
    'use strict';

    // Chạy khi dialog load
    $(document).on('dialog-ready', function() {
        initShowHide();
    });

    function initShowHide() {
        // Tìm select field trigger
        var $select = $('[name="./layoutType"]');
        if (!$select.length) return;

        // Lấy Coral select component
        Coral.commons.ready($select[0], function(selectEl) {
            // Trạng thái ban đầu
            toggleFields(selectEl.value);

            // Lắng nghe changes
            selectEl.on('change', function() {
                toggleFields(selectEl.value);
            });
        });
    }

    function toggleFields(value) {
        var $imageField = $('[name="./backgroundImage"]').closest('.coral-Form-fieldwrapper');
        var $colorField = $('[name="./backgroundColor"]').closest('.coral-Form-fieldwrapper');

        if (value === 'image') {
            $imageField.show();
            $colorField.hide();
        } else if (value === 'color') {
            $imageField.hide();
            $colorField.show();
        } else {
            $imageField.show();
            $colorField.show();
        }
    }

})(jQuery, Coral);

Custom validation

File: ui.apps/.../clientlibs/clientlib-dialog/js/validation.js

javascript
(function($, Coral) {
    'use strict';

    // Đăng ký custom validator
    $(window).adaptTo('foundation-registry').register(
        'foundation.validation.validator',
        {
            // CSS selector để match field
            selector: '[data-validation="url-pattern"]',

            // Validation function
            validate: function(el) {
                var value = el.value;
                if (!value) return; // Bỏ qua empty (dùng 'required' cho việc đó)

                var urlPattern = /^https?:\/\/.+/;
                if (!urlPattern.test(value)) {
                    return 'Vui lòng nhập URL hợp lệ bắt đầu bằng http:// hoặc https://';
                }
            }
        }
    );

})(jQuery, Coral);

Thêm validator vào dialog field qua granite:data:

xml
<linkUrl
    jcr:primaryType="nt:unstructured"
    sling:resourceType="granite/ui/components/coral/foundation/form/textfield"
    fieldLabel="Link URL"
    name="./linkUrl"
    validation="url-pattern"/>

Setting default values động

Setting default date là ngày hôm nay:

javascript
(function($, Coral) {
    'use strict';

    $(document).on('dialog-ready', function() {
        var $dateField = $('[name="./publishDate"]');
        if (!$dateField.length) return;

        Coral.commons.ready($dateField[0], function(datePicker) {
            // Chỉ set nếu field empty (component mới)
            if (!datePicker.value) {
                var today = new Date().toISOString().split('T')[0];
                datePicker.value = today;
            }
        });
    });

})(jQuery, Coral);

Loading dialog clientlib

Đăng ký dialog clientlib với category cq.authoring.dialog hoặc reference nó như thuộc tính extraClientlibs trên component:

File: ui.apps/.../clientlibs/clientlib-dialog/.content.xml

xml
<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:cq="http://www.day.com/jcr/cq/1.0"
    jcr:primaryType="cq:ClientLibraryFolder"
    allowProxy="{Boolean}true"
    categories="[cq.authoring.dialog]"
    dependencies="[coralui3]"/>

💡 Mẹo: Category cq.authoring.dialog được load cho tất cả dialogs. Nếu script của bạn chỉ nên chạy cho một component cụ thể, scope nó bằng cách check for a field unique to that dialog:

javascript
$(document).on('dialog-ready', function() {
    var $myField = $('[name="./myUniqueFieldName"]');
    if (!$myField.length) return; // Không phải dialog của chúng ta
    // ... custom logic ...
});

Coral UI JavaScript API Patterns

Coral.commons.ready()

Đợi cho đến khi Coral component được fully initialised trước khi tương tác:

javascript
var element = document.querySelector('coral-select');
Coral.commons.ready(element, function(readyElement) {
    // Component đã fully initialised và ready
    console.log('Selected value:', readyElement.value);
});

Event handling với .on()

Coral components mở rộng HTMLElement và hỗ trợ standard DOM events plus Coral-specific events:

javascript
// Coral event
dialog.on('coral-overlay:open', function() { /* dialog opened */ });
dialog.on('coral-overlay:close', function() { /* dialog closed */ });

// Standard DOM event on Coral element
select.on('change', function() { /* value changed */ });

// jQuery-style với delegation
$(document).on('change', 'coral-select[name="./category"]', function(e) {
    console.log('Category changed:', e.target.value);
});

Các Coral events phổ biến

EventComponentKích hoạt khi
changeSelect, Checkbox, Radio, SwitchValue changes
coral-overlay:openDialog, PopoverOverlay opens
coral-overlay:closeDialog, PopoverOverlay closes
coral-overlay:beforeopenDialog, PopoverBefore overlay opens (cancellable)
coral-overlay:beforecloseDialog, PopoverBefore overlay closes (cancellable)
coral-collection:addMultifield, TagListItem added
coral-collection:removeMultifield, TagListItem removed
clickButtonButton clicked
inputTextfield, TextareaUser types

foundation-registry

Granite UI registry được sử dụng cho validators, adapters, và các extension points khác:

javascript
var registry = $(window).adaptTo('foundation-registry');

// Register a validator
registry.register('foundation.validation.validator', { ... });

// Register a condition (for show/hide)
registry.register('foundation.condition', { ... });

// Register an adapter
registry.register('foundation.adapters', { ... });

foundation-contentloaded

Kích hoạt khi nội dung mới được load vào DOM (ví dụ: dialog mở, multifield item được thêm):

javascript
$(document).on('foundation-contentloaded', function(e) {
    // New content đã được load vào e.target
    // Re-initialise any custom logic cho dynamically added fields
    var $newContent = $(e.target);
    $newContent.find('[data-my-widget]').each(function() {
        initMyWidget(this);
    });
});

Xây dựng Custom Dialog Field

Cho các requirements mà Coral UI's built-in fields không đáp ứng được, bạn có thể tạo custom Granite UI field component mà render Coral UI markup:

Server-side (Granite UI field)

File: ui.apps/apps/myproject/components/fields/color-picker/color-picker.html

html
<sly data-sly-use.field="com.adobe.granite.ui.components.Field"/>
<div class="coral-Form-fieldwrapper"
     data-sly-use.cfg="com.adobe.granite.ui.components.Config">

    <label class="coral-Form-fieldlabel"
           data-sly-test="${cfg.fieldLabel}">${cfg.fieldLabel}</label>

    <div class="myproject-color-picker">
        <input is="coral-textfield"
               name="${field.name}"
               value="${field.value}"
               type="text"
               class="myproject-color-picker__input"
               placeholder="${cfg.emptyText || '#000000'}"/>
        <div class="myproject-color-picker__preview"
             style="background-color: ${field.value || '#000000'}"></div>
    </div>

    <coral-icon icon="infoCircle"
                size="S"
                class="coral-Form-fieldinfo"
                data-sly-test="${cfg.fieldDescription}"
                title="${cfg.fieldDescription}"></coral-icon>
</div>

Client-side (JavaScript enhancement)

File: ui.apps/.../clientlibs/clientlib-dialog/js/color-picker.js

javascript
(function($, Coral) {
    'use strict';

    $(document).on('foundation-contentloaded', function() {
        $('.myproject-color-picker').each(function() {
            var $picker = $(this);
            var $input = $picker.find('.myproject-color-picker__input');
            var $preview = $picker.find('.myproject-color-picker__preview');

            // Update preview on input change
            $input.on('input', function() {
                $preview.css('background-color', $input.val() || '#000000');
            });
        });
    });

})(jQuery, Coral);

Sử dụng custom field trong dialog

xml
<backgroundColor
    jcr:primaryType="nt:unstructured"
    sling:resourceType="myproject/components/fields/color-picker"
    fieldLabel="Màu nền"
    fieldDescription="Nhập mã hex color"
    emptyText="#ffffff"
    name="./backgroundColor"/>

Theming và CSS Classes

Coral UI sử dụng các CSS utility classes cho layout và spacing:

Layout classes

ClassMục đích
coral-Form-fieldwrapperWraps a form field (label + input + description)
coral-Form-fieldlabelField label text
coral-Form-fieldinfoHelp icon / description
coral-Form-fieldThe input element itself
coral--darkDark theme (applied to a container)
coral--lightLight theme
coral--largestLargest text size
coral--largeLarge text size

Spacing với u-coral-*

html
<!-- Margin -->
<div class="u-coral-margin">Standard margin</div>
<div class="u-coral-marginTop">Top margin only</div>
<div class="u-coral-marginBottom">Bottom margin only</div>

<!-- Padding -->
<div class="u-coral-padding">Standard padding</div>
<div class="u-coral-noPadding">Remove padding</div>

<!-- Text alignment -->
<div class="u-coral-textAlignCenter">Centred text</div>
<div class="u-coral-textAlignRight">Right-aligned text</div>

<!-- Visibility -->
<div class="u-coral-screenReaderOnly">Hidden visually, accessible to screen readers</div>

Best Practices cho AEM 6.5 (2026)

1. Luôn sử dụng Coral.commons.ready() trước khi access components

Coral components initialise không đồng bộ. Luôn sử dụng Coral.commons.ready() hoặc foundation-contentloaded event trước khi đọc values hoặc attach listeners.

2. Scope dialog scripts để tránh conflicts

Dialog clientlibs với category cq.authoring.dialog chạy cho mọi dialog. Luôn check for a unique field name trước khi executing logic của bạn.

3. Không manipulate Coral DOM internals

Coral components tự quản lý internal DOM structure của chúng (shadow DOM). Không rely vào hoặc manipulate internal elements -- sử dụng component's JavaScript API thay thế:

javascript
// ❌ Bad: manipulating internal DOM
select.querySelector('.coral-Select-trigger').style.color = 'red';

// ✅ Good: using the component API
select.variant = 'warning';
select.disabled = true;

4. Sử dụng granite:data cho custom data attributes

Pass custom data từ dialog XML đến client-side JavaScript của bạn:

xml
<myField
    jcr:primaryType="nt:unstructured"
    sling:resourceType="granite/ui/components/coral/foundation/form/textfield"
    name="./title">
    <granite:data
        jcr:primaryType="nt:unstructured"
        max-words="{Long}50"
        show-counter="{Boolean}true"/>
</myField>
javascript
// Đọc trong JS
var maxWords = $field.data('max-words');     // 50
var showCounter = $field.data('show-counter'); // true

5. Ưu tiên built-in Granite UI fields

Trước khi building custom field, check xem có existing Granite UI field type hoặc Coral component nào cover need của bạn không. Custom fields add maintenance overhead và có thể break khi AEM upgrades.

6. Cập nhật 2026: Tối ưu cho AEM 6.5 on-premise

  • Performance: Sử dụng async loading cho clientlibs lớn
  • Security: Validate tất cả inputs trong custom dialogs
  • Accessibility: Đảm bảo WCAG 2.1 compliance cho author UI
  • Browser support: AEM 6.5 Coral UI 3 support modern browsers (Chrome 90+, Firefox 88+, Edge 90+)

Common Pitfalls và Solutions

Vấn đềGiải pháp
Coral is not definedĐảm bảo clientlib của bạn có coralui3 như một dependency
Component API methods return undefinedSử dụng Coral.commons.ready() - component chưa được initialised
Dialog script chạy cho wrong componentScope script của bạn bằng cách check for a unique field name
Styles break sau AEM upgradeKhông rely vào internal Coral DOM structure; sử dụng public API
foundation-contentloaded fires nhiều lầnBình thường - nó fires cho mỗi lần content load mới (dialog open, multifield add); make init logic idempotent
Custom field không save valuesĐảm bảo <input>name attribute matching ./propertyName
jQuery $ không availableSử dụng (function($, Coral) { ... })(jQuery, Coral); wrapper

Tài nguyên Tham khảo

Tài liệu chính thức

Xem thêm

  • Touch UI (Author UI) - Touch UI architecture
  • Overlays - Customising existing AEM UI
  • Render Conditions - Showing/hiding UI elements
  • Component Dialogs - Dialog field types và XML structure
  • Client Libraries - Loading clientlibs
  • Custom Component Guide - Building components với dialog clientlibs
  • HTL Templates - Server-side rendering

Kết luận

Coral UI là nền tảng quan trọng cho việc phát triển author UI trong AEM 6.5. Hiểu rõ sự khác biệt giữa Granite UI (server-side) và Coral UI (client-side), nắm vững các components phổ biến, và áp dụng best practices sẽ giúp bạn xây dựng các custom dialogs và admin interfaces hiệu quả, maintainable và compatible với AEM 6.5 on-premise trong năm 2026.

Lưu ý quan trọng: AEM 6.5 vẫn đang được Adobe support đến tháng 4/2026 (với Extended Support). Coral UI 3 là version ổn định nhất cho AEM 6.5. Không upgrade lên Coral Spectrum (v4) vì nó chỉ compatible với AEM as a Cloud Service và AEM 6.6+.

AEM 6.5 On-Premise Developer Notes