I’ll build this as a reusable RX Theme static chunk: safe copy-code buttons, toolbar actions, accessibility labels, toast messages, keyboard support, fallback clipboard methods, and WordPress-friendly no-dependency JavaScript.
Yes friend — create this file:
assets/static-js/static-chunks-js/chunk-012-copy-code.js
Paste this full advanced code inside it.
/*!
* RX Theme - Static Chunk 012: Advanced Copy Code System
* File: assets/static-js/static-chunks-js/chunk-012-copy-code.js
* Theme: RX Theme
* Author: RxHarun
*
* Features:
* - Auto adds copy buttons to code blocks
* - Works with <pre><code>, <pre>, and custom selectors
* - Clipboard API with fallback method
* - Accessible buttons with aria-label
* - Copy success/error toast
* - Optional line numbers
* - Optional code language label
* - Optional select-all button
* - Optional collapse/expand for long code
* - Optional double-click copy
* - Prevents duplicate initialization
* - Works after AJAX/dynamic content
*/
(function () {
'use strict';
var RX_COPY_CODE_VERSION = '1.0.0';
var DEFAULT_OPTIONS = {
root: document,
selector: 'pre',
codeSelector: 'code',
wrapperClass: 'rx-code-copy-wrapper',
toolbarClass: 'rx-code-copy-toolbar',
buttonClass: 'rx-code-copy-button',
selectButtonClass: 'rx-code-select-button',
collapseButtonClass: 'rx-code-collapse-button',
copiedClass: 'is-copied',
failedClass: 'is-failed',
initializedAttr: 'data-rx-copy-code-init',
languageAttr: 'data-language',
copiedText: 'Copied!',
copyText: 'Copy',
copyErrorText: 'Copy failed',
selectText: 'Select',
collapseText: 'Collapse',
expandText: 'Expand',
enableToast: true,
enableLanguageLabel: true,
enableSelectButton: true,
enableCollapseButton: true,
enableDoubleClickCopy: true,
enableKeyboardShortcut: true,
enableLineNumbers: false,
minLinesForCollapse: 18,
buttonResetDelay: 1600,
toastDuration: 2200,
maxToastCount: 3
};
var state = {
toastContainer: null,
activeToasts: [],
observer: null,
options: null
};
function extend(target) {
var sources = Array.prototype.slice.call(arguments, 1);
sources.forEach(function (source) {
if (!source) return;
Object.keys(source).forEach(function (key) {
target[key] = source[key];
});
});
return target;
}
function ready(callback) {
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', callback, { once: true });
} else {
callback();
}
}
function isElement(node) {
return node && node.nodeType === 1;
}
function createElement(tag, className, text) {
var element = document.createElement(tag);
if (className) {
element.className = className;
}
if (typeof text === 'string') {
element.textContent = text;
}
return element;
}
function normalizeText(text) {
if (!text) return '';
return String(text)
.replace(/\u00a0/g, ' ')
.replace(/\r\n/g, '\n')
.replace(/\r/g, '\n')
.replace(/\n+$/g, '');
}
function getCodeElement(pre, options) {
if (!pre) return null;
if (pre.matches && pre.matches(options.codeSelector)) {
return pre;
}
return pre.querySelector(options.codeSelector) || pre;
}
function getCodeText(pre, options) {
var codeElement = getCodeElement(pre, options);
if (!codeElement) return '';
var clone = codeElement.cloneNode(true);
var ignored = clone.querySelectorAll(
'.rx-code-copy-toolbar, .rx-code-language-label, .rx-code-line-number, .rx-code-line-numbers'
);
ignored.forEach(function (node) {
node.remove();
});
return normalizeText(clone.innerText || clone.textContent || '');
}
function getLineCount(text) {
if (!text) return 0;
return text.split('\n').length;
}
function detectLanguage(pre, codeElement) {
var language = '';
if (pre.getAttribute('data-language')) {
language = pre.getAttribute('data-language');
}
if (!language && codeElement && codeElement.getAttribute('data-language')) {
language = codeElement.getAttribute('data-language');
}
if (!language && codeElement && codeElement.className) {
var match = String(codeElement.className).match(/language-([a-zA-Z0-9_-]+)/);
if (match && match[1]) {
language = match[1];
}
}
if (!language && pre.className) {
var preMatch = String(pre.className).match(/language-([a-zA-Z0-9_-]+)/);
if (preMatch && preMatch[1]) {
language = preMatch[1];
}
}
if (!language) {
language = 'code';
}
return language
.replace(/-/g, ' ')
.replace(/_/g, ' ')
.trim()
.toUpperCase();
}
function copyUsingClipboardApi(text) {
if (
navigator.clipboard &&
window.isSecureContext &&
typeof navigator.clipboard.writeText === 'function'
) {
return navigator.clipboard.writeText(text);
}
return Promise.reject(new Error('Clipboard API unavailable'));
}
function copyUsingFallback(text) {
return new Promise(function (resolve, reject) {
var textarea = document.createElement('textarea');
textarea.value = text;
textarea.setAttribute('readonly', '');
textarea.setAttribute('aria-hidden', 'true');
textarea.style.position = 'fixed';
textarea.style.top = '-9999px';
textarea.style.left = '-9999px';
textarea.style.width = '1px';
textarea.style.height = '1px';
textarea.style.opacity = '0';
textarea.style.pointerEvents = 'none';
document.body.appendChild(textarea);
textarea.focus();
textarea.select();
try {
var successful = document.execCommand('copy');
document.body.removeChild(textarea);
if (successful) {
resolve();
} else {
reject(new Error('Fallback copy failed'));
}
} catch (error) {
document.body.removeChild(textarea);
reject(error);
}
});
}
function copyText(text) {
return copyUsingClipboardApi(text).catch(function () {
return copyUsingFallback(text);
});
}
function ensureToastContainer() {
if (state.toastContainer) {
return state.toastContainer;
}
var container = createElement('div', 'rx-copy-toast-container');
container.setAttribute('aria-live', 'polite');
container.setAttribute('aria-atomic', 'true');
document.body.appendChild(container);
state.toastContainer = container;
return container;
}
function showToast(message, type, options) {
if (!options.enableToast) return;
var container = ensureToastContainer();
while (state.activeToasts.length >= options.maxToastCount) {
var oldToast = state.activeToasts.shift();
if (oldToast && oldToast.parentNode) {
oldToast.parentNode.removeChild(oldToast);
}
}
var toast = createElement('div', 'rx-copy-toast rx-copy-toast-' + type, message);
container.appendChild(toast);
state.activeToasts.push(toast);
window.setTimeout(function () {
toast.classList.add('is-visible');
}, 20);
window.setTimeout(function () {
toast.classList.remove('is-visible');
window.setTimeout(function () {
if (toast.parentNode) {
toast.parentNode.removeChild(toast);
}
state.activeToasts = state.activeToasts.filter(function (item) {
return item !== toast;
});
}, 300);
}, options.toastDuration);
}
function setButtonState(button, stateName, text, options) {
if (!button) return;
button.classList.remove(options.copiedClass);
button.classList.remove(options.failedClass);
if (stateName === 'copied') {
button.classList.add(options.copiedClass);
}
if (stateName === 'failed') {
button.classList.add(options.failedClass);
}
button.textContent = text;
button.setAttribute('aria-label', text);
}
function resetCopyButton(button, options) {
window.setTimeout(function () {
if (!button) return;
button.classList.remove(options.copiedClass);
button.classList.remove(options.failedClass);
button.textContent = options.copyText;
button.setAttribute('aria-label', options.copyText);
}, options.buttonResetDelay);
}
function selectCode(pre, options) {
var codeElement = getCodeElement(pre, options);
if (!codeElement) return;
var range = document.createRange();
var selection = window.getSelection();
range.selectNodeContents(codeElement);
selection.removeAllRanges();
selection.addRange(range);
showToast('Code selected', 'info', options);
}
function toggleCollapse(pre, button, options) {
var isCollapsed = pre.classList.toggle('rx-code-is-collapsed');
if (isCollapsed) {
button.textContent = options.expandText;
button.setAttribute('aria-label', options.expandText);
button.setAttribute('aria-expanded', 'false');
} else {
button.textContent = options.collapseText;
button.setAttribute('aria-label', options.collapseText);
button.setAttribute('aria-expanded', 'true');
}
}
function addLanguageLabel(wrapper, pre, codeElement, options) {
if (!options.enableLanguageLabel) return;
if (wrapper.querySelector('.rx-code-language-label')) return;
var language = detectLanguage(pre, codeElement);
var label = createElement('span', 'rx-code-language-label', language);
label.setAttribute(options.languageAttr, language);
wrapper.appendChild(label);
}
function addLineNumbers(pre, text, options) {
if (!options.enableLineNumbers) return;
if (pre.querySelector('.rx-code-line-numbers')) return;
var lineCount = getLineCount(text);
if (lineCount < 2) return;
var numbers = createElement('span', 'rx-code-line-numbers');
numbers.setAttribute('aria-hidden', 'true');
var fragment = document.createDocumentFragment();
for (var i = 1; i <= lineCount; i += 1) {
var line = createElement('span', 'rx-code-line-number', String(i));
fragment.appendChild(line);
}
numbers.appendChild(fragment);
pre.insertBefore(numbers, pre.firstChild);
pre.classList.add('rx-code-has-line-numbers');
}
function createToolbar(pre, options) {
var toolbar = createElement('div', options.toolbarClass);
toolbar.setAttribute('role', 'toolbar');
toolbar.setAttribute('aria-label', 'Code tools');
var copyButton = createElement('button', options.buttonClass, options.copyText);
copyButton.type = 'button';
copyButton.setAttribute('aria-label', options.copyText);
copyButton.addEventListener('click', function () {
var text = getCodeText(pre, options);
if (!text.trim()) {
setButtonState(copyButton, 'failed', options.copyErrorText, options);
showToast(options.copyErrorText, 'error', options);
resetCopyButton(copyButton, options);
return;
}
copyText(text)
.then(function () {
setButtonState(copyButton, 'copied', options.copiedText, options);
showToast(options.copiedText, 'success', options);
resetCopyButton(copyButton, options);
})
.catch(function () {
setButtonState(copyButton, 'failed', options.copyErrorText, options);
showToast(options.copyErrorText, 'error', options);
resetCopyButton(copyButton, options);
});
});
toolbar.appendChild(copyButton);
if (options.enableSelectButton) {
var selectButton = createElement('button', options.selectButtonClass, options.selectText);
selectButton.type = 'button';
selectButton.setAttribute('aria-label', options.selectText);
selectButton.addEventListener('click', function () {
selectCode(pre, options);
});
toolbar.appendChild(selectButton);
}
if (options.enableCollapseButton) {
var text = getCodeText(pre, options);
var lineCount = getLineCount(text);
if (lineCount >= options.minLinesForCollapse) {
var collapseButton = createElement(
'button',
options.collapseButtonClass,
options.expandText
);
collapseButton.type = 'button';
collapseButton.setAttribute('aria-label', options.expandText);
collapseButton.setAttribute('aria-expanded', 'false');
pre.classList.add('rx-code-is-collapsed');
pre.setAttribute('data-rx-code-lines', String(lineCount));
collapseButton.addEventListener('click', function () {
toggleCollapse(pre, collapseButton, options);
});
toolbar.appendChild(collapseButton);
}
}
return toolbar;
}
function wrapPre(pre, options) {
if (!isElement(pre)) return null;
if (pre.getAttribute(options.initializedAttr) === 'true') {
return null;
}
if (pre.closest('.' + options.wrapperClass)) {
pre.setAttribute(options.initializedAttr, 'true');
return pre.closest('.' + options.wrapperClass);
}
var wrapper = createElement('div', options.wrapperClass);
pre.parentNode.insertBefore(wrapper, pre);
wrapper.appendChild(pre);
return wrapper;
}
function initSingleCodeBlock(pre, customOptions) {
var options = extend({}, DEFAULT_OPTIONS, state.options || {}, customOptions || {});
if (!pre || !pre.parentNode) return;
if (pre.getAttribute(options.initializedAttr) === 'true') return;
var codeElement = getCodeElement(pre, options);
var text = getCodeText(pre, options);
if (!text.trim()) return;
var wrapper = wrapPre(pre, options);
if (!wrapper) return;
wrapper.classList.add('rx-code-copy-ready');
pre.setAttribute(options.initializedAttr, 'true');
pre.classList.add('rx-code-block');
if (codeElement && codeElement !== pre) {
codeElement.classList.add('rx-code-inner');
}
addLanguageLabel(wrapper, pre, codeElement, options);
addLineNumbers(pre, text, options);
if (!wrapper.querySelector('.' + options.toolbarClass)) {
var toolbar = createToolbar(pre, options);
wrapper.appendChild(toolbar);
}
if (options.enableDoubleClickCopy) {
pre.addEventListener('dblclick', function () {
var currentText = getCodeText(pre, options);
if (!currentText.trim()) return;
copyText(currentText)
.then(function () {
showToast(options.copiedText, 'success', options);
})
.catch(function () {
showToast(options.copyErrorText, 'error', options);
});
});
}
}
function initCodeBlocks(customOptions) {
var options = extend({}, DEFAULT_OPTIONS, state.options || {}, customOptions || {});
var root = options.root || document;
state.options = options;
if (!root.querySelectorAll) return;
var blocks = root.querySelectorAll(options.selector);
blocks.forEach(function (pre) {
initSingleCodeBlock(pre, options);
});
}
function observeDynamicContent(options) {
if (state.observer) return;
if (!('MutationObserver' in window)) return;
state.observer = new MutationObserver(function (mutations) {
var shouldScan = false;
mutations.forEach(function (mutation) {
if (shouldScan) return;
mutation.addedNodes.forEach(function (node) {
if (shouldScan) return;
if (!isElement(node)) return;
if (
node.matches &&
(node.matches(options.selector) || node.querySelector(options.selector))
) {
shouldScan = true;
}
});
});
if (shouldScan) {
window.requestAnimationFrame(function () {
initCodeBlocks(options);
});
}
});
state.observer.observe(document.body, {
childList: true,
subtree: true
});
}
function handleKeyboardShortcut(options) {
if (!options.enableKeyboardShortcut) return;
document.addEventListener('keydown', function (event) {
var isMac = navigator.platform.toUpperCase().indexOf('MAC') >= 0;
var modifier = isMac ? event.metaKey : event.ctrlKey;
if (!modifier || event.shiftKey || event.altKey) return;
if (String(event.key).toLowerCase() !== 'c') return;
var active = document.activeElement;
if (!active) return;
var wrapper = active.closest && active.closest('.' + options.wrapperClass);
if (!wrapper) return;
var pre = wrapper.querySelector(options.selector);
if (!pre) return;
var selection = window.getSelection();
if (selection && String(selection).trim()) {
return;
}
event.preventDefault();
var text = getCodeText(pre, options);
if (!text.trim()) return;
copyText(text)
.then(function () {
showToast(options.copiedText, 'success', options);
})
.catch(function () {
showToast(options.copyErrorText, 'error', options);
});
});
}
function injectBaseStyles() {
if (document.getElementById('rx-copy-code-style')) return;
var css = [
'.rx-code-copy-wrapper{position:relative;margin:1.5rem 0;}',
'.rx-code-copy-wrapper pre{position:relative;overflow:auto;padding-top:3rem;}',
'.rx-code-copy-toolbar{position:absolute;top:.5rem;right:.5rem;z-index:5;display:flex;gap:.4rem;align-items:center;}',
'.rx-code-copy-toolbar button{border:1px solid rgba(120,120,120,.35);border-radius:.45rem;background:rgba(255,255,255,.92);color:#222;font-size:.78rem;line-height:1;padding:.48rem .65rem;cursor:pointer;box-shadow:0 1px 3px rgba(0,0,0,.08);}',
'.rx-code-copy-toolbar button:hover{background:#fff;}',
'.rx-code-copy-toolbar button:focus{outline:2px solid currentColor;outline-offset:2px;}',
'.rx-code-copy-button.is-copied{font-weight:700;}',
'.rx-code-copy-button.is-failed{font-weight:700;}',
'.rx-code-language-label{position:absolute;top:.65rem;left:.75rem;z-index:4;font-size:.72rem;font-weight:700;letter-spacing:.06em;text-transform:uppercase;opacity:.72;}',
'.rx-code-is-collapsed{max-height:24rem;overflow:hidden;}',
'.rx-code-is-collapsed:after{content:"";position:absolute;left:0;right:0;bottom:0;height:4rem;background:linear-gradient(to bottom,rgba(255,255,255,0),rgba(255,255,255,.9));pointer-events:none;}',
'.rx-code-has-line-numbers{display:grid;grid-template-columns:auto 1fr;gap:0;}',
'.rx-code-line-numbers{user-select:none;text-align:right;padding-right:1rem;margin-right:1rem;border-right:1px solid rgba(120,120,120,.25);opacity:.55;}',
'.rx-code-line-number{display:block;line-height:inherit;}',
'.rx-code-inner{min-width:0;}',
'.rx-copy-toast-container{position:fixed;right:1rem;bottom:1rem;z-index:99999;display:flex;flex-direction:column;gap:.5rem;pointer-events:none;}',
'.rx-copy-toast{opacity:0;transform:translateY(8px);transition:opacity .25s ease,transform .25s ease;border-radius:.6rem;background:#111;color:#fff;padding:.75rem 1rem;font-size:.9rem;box-shadow:0 8px 24px rgba(0,0,0,.18);}',
'.rx-copy-toast.is-visible{opacity:1;transform:translateY(0);}',
'@media (prefers-color-scheme:dark){.rx-code-copy-toolbar button{background:rgba(24,24,24,.92);color:#f5f5f5;border-color:rgba(255,255,255,.18);}.rx-code-copy-toolbar button:hover{background:#111;}.rx-code-is-collapsed:after{background:linear-gradient(to bottom,rgba(20,20,20,0),rgba(20,20,20,.9));}}'
].join('');
var style = document.createElement('style');
style.id = 'rx-copy-code-style';
style.textContent = css;
document.head.appendChild(style);
}
function init(customOptions) {
var options = extend({}, DEFAULT_OPTIONS, customOptions || {});
state.options = options;
ready(function () {
injectBaseStyles();
initCodeBlocks(options);
observeDynamicContent(options);
handleKeyboardShortcut(options);
});
}
window.RXCopyCode = {
version: RX_COPY_CODE_VERSION,
init: init,
refresh: initCodeBlocks,
copyText: copyText,
selectCode: selectCode
};
init(window.rxCopyCodeOptions || {});
})();
For loading in functions.php, use this:
function rx_theme_enqueue_copy_code_chunk() {
wp_enqueue_script(
'rx-theme-copy-code-chunk',
get_template_directory_uri() . '/assets/static-js/static-chunks-js/chunk-012-copy-code.js',
array(),
wp_get_theme()->get( 'Version' ),
true
);
}
add_action( 'wp_enqueue_scripts', 'rx_theme_enqueue_copy_code_chunk' );
Optional advanced settings before the script loads:
function rx_theme_copy_code_inline_options() {
wp_add_inline_script(
'rx-theme-copy-code-chunk',
'window.rxCopyCodeOptions = {
enableToast: true,
enableLanguageLabel: true,
enableSelectButton: true,
enableCollapseButton: true,
enableDoubleClickCopy: true,
enableKeyboardShortcut: true,
enableLineNumbers: false,
minLinesForCollapse: 18,
copiedText: "Copied!",
copyText: "Copy",
copyErrorText: "Copy failed"
};',
'before'
);
}
add_action( 'wp_enqueue_scripts', 'rx_theme_copy_code_inline_options', 20 );
Best RX Theme path:
rx-theme/
└── assets/
└── static-js/
└── static-chunks-js/
└── chunk-012-copy-code.js
This file is safe for your medical article pages, tutorial pages, and developer/code guide posts. It will automatically add copy buttons to code blocks without needing jQuery.