How to auto-expand CC and BCC fields by default?

srohan24
Tera Contributor

I have a requirement to auto-expand the CC and BCC fields by default when users open the Email (Compose Email) from a form (e.g., Case/Incident) in ServiceNow.

  • Current Behavior
    • When users click on Email / Compose, the email client opens
    • The CC and BCC fields are collapsed by default
    • Users need to manually click on “CC” and “BCC” to expand them
  • Requirement
    • CC and BCC fields should be visible (expanded) by default when the email client loads
    • This should apply for all users across the platform

Refer the attached screenshots. Image 2 is current behavior, Image 3 is requirement.

3 REPLIES 3

Naveen20
ServiceNow Employee

The CC and BCC fields in the Compose Email dialog are collapsed by default and toggled via client-side JavaScript. The most reliable and upgrade-safe approach is a Global UI Script that detects when the email compose dialog opens and programmatically expands those fields.

 

Try this
System UI > UI Scripts and create a new record:

Field Value
Name Auto Expand CC BCC 
Global true
Active true

Script:

 
/*
 * Auto-expand CC and BCC fields in Compose Email dialog.
 * Uses MutationObserver to detect when the email dialog is injected into the DOM,
 * then triggers the CC/BCC toggle so fields are visible by default.
 */
(function() {
    'use strict';

    function expandCcBcc(dialogEl) {
        // Look for the CC/Bcc toggle links/buttons inside the email compose dialog
        // In the standard email client the collapsed state shows "Cc" and "Bcc" as
        // clickable links in the To row. Clicking them reveals the full input fields.
        var toggles = dialogEl.querySelectorAll(
            '.email-cc-bcc-toggle, a[data-action="show-cc"], a[data-action="show-bcc"], ' +
            '.cc-bcc-link, .toggle-cc, .toggle-bcc'
        );

        // Fallback: find any anchor/span whose text is exactly "Cc" or "Bcc"
        if (!toggles || toggles.length === 0) {
            var allLinks = dialogEl.querySelectorAll('a, span.btn, button');
            toggles = [];
            for (var i = 0; i < allLinks.length; i++) {
                var txt = (allLinks[i].textContent || '').trim();
                if (txt === 'Cc' || txt === 'Bcc') {
                    toggles.push(allLinks[i]);
                }
            }
        }

        for (var j = 0; j < toggles.length; j++) {
            toggles[j].click();
        }
    }

    // Observe the DOM for the email compose dialog appearing
    var observer = new MutationObserver(function(mutations) {
        mutations.forEach(function(mutation) {
            for (var k = 0; k < mutation.addedNodes.length; k++) {
                var node = mutation.addedNodes[k];
                if (node.nodeType !== 1) continue; // element nodes only

                // Check if this node IS or CONTAINS the email compose dialog
                var dialog = null;
                if (node.classList && (
                    node.classList.contains('email-compose') ||
                    node.classList.contains('email_client') ||
                    node.id === 'email_client_iframe'
                )) {
                    dialog = node;
                } else if (node.querySelector) {
                    dialog = node.querySelector(
                        '.email-compose, .email_client, #email_client_iframe'
                    );
                }

                if (dialog) {
                    // Small delay to let the dialog fully render its internal fields
                    setTimeout(function() {
                        expandCcBcc(dialog);
                    }, 500);
                }

                // Handle iframe-based email client (classic UI)
                if (node.tagName === 'IFRAME' || (node.querySelector && node.querySelector('iframe'))) {
                    var iframe = (node.tagName === 'IFRAME') ? node : node.querySelector('iframe');
                    if (iframe) {
                        iframe.addEventListener('load', function() {
                            try {
                                var iframeDoc = iframe.contentDocument || iframe.contentWindow.document;
                                setTimeout(function() {
                                    expandCcBcc(iframeDoc);
                                }, 500);
                            } catch (e) {
                                // Cross-origin restrictions – skip
                            }
                        });
                    }
                }
            }
        });
    });

    observer.observe(document.body, { childList: true, subtree: true });
})();

I tried but didn't work, do I need to change anything in the script?

Naveen20
ServiceNow Employee

Try these options

 

Option 1: CSS Style Sheet Override

Navigate to System UI > Style Sheets, create a new record:

Name: Force CC BCC Visible

.email-form .cc-row,
.email-form .bcc-row,
.compose-email .cc-row,
.compose-email .bcc-row,
tr.cc-row,
tr.bcc-row,
.email_cc_field,
.email_bcc_field {
    display: table-row !important;
    visibility: visible !important;
}

.cc-bcc-link,
.email-cc-bcc-toggle,
a[data-action="show-cc"],
a[data-action="show-bcc"] {
    display: none !important;
}

This forces the CC/BCC rows visible and hides the toggle links since they're no longer needed.

Option 2: UI Script Targeting the Email Client Iframe

The Compose Email dialog loads inside an iframe (email_client.do), which is why a standard Global UI Script can't reach its DOM directly. Navigate to System UI > UI Scripts, create a new record with Global = true:

(function() {
    'use strict';

    function expandCcBccInDoc(doc) {
        if (!doc) return;
        try {
            var candidates = doc.querySelectorAll('a, span, button, div');
            for (var i = 0; i < candidates.length; i++) {
                var txt = (candidates[i].textContent || '').trim();
                if (txt === 'Cc' || txt === 'Bcc') {
                    candidates[i].click();
                }
            }
        } catch (e) { /* cross-origin or not ready */ }
    }

    function tryExpandInIframe(iframe) {
        var attempts = 0;
        var interval = setInterval(function() {
            attempts++;
            try {
                var iDoc = iframe.contentDocument || iframe.contentWindow.document;
                if (iDoc && iDoc.readyState === 'complete') {
                    setTimeout(function() {
                        expandCcBccInDoc(iDoc);
                    }, 800);
                    clearInterval(interval);
                }
            } catch (e) { /* not ready */ }
            if (attempts >= 20) clearInterval(interval);
        }, 300);
    }

    var observer = new MutationObserver(function(mutations) {
        mutations.forEach(function(m) {
            for (var k = 0; k < m.addedNodes.length; k++) {
                var node = m.addedNodes[k];
                if (node.nodeType !== 1) continue;
                var iframes = (node.tagName === 'IFRAME') ? [node] :
                    (node.querySelectorAll ? node.querySelectorAll('iframe') : []);
                for (var f = 0; f < iframes.length; f++) {
                    var src=(iframes[f].src || '').toLowerCase();
                    if (src.indexOf('email') > -1) {
                        tryExpandInIframe(iframes[f]);
                    }
                }
            }
        });
    });

    observer.observe(document.body, { childList: true, subtree: true });
})();

Option 3: UI Macro Override

If the above options don't work, you can override the OOB email_client UI Macro. Navigate to System UI > UI Macros, find the email_client macro, insert to create a new version, and add this snippet at the bottom of the client-side script block:

addAfterPageLoadedEvent(function() {
    // Simulate click on Cc and Bcc toggles after email client renders
    setTimeout(function() {
        $$('a').each(function(el) {
            var t = el.textContent.trim();
            if (t === 'Cc' || t === 'Bcc') el.click();
        });
    }, 500);
});

Note on Option 3: This directly modifies an OOB component, so document the change and be prepared to re-apply after upgrades. Options 1 and 2 are upgrade-safe.