diff --git a/_includes/footer.html b/_includes/footer.html
index 7d2e03d067..f4d72db177 100644
--- a/_includes/footer.html
+++ b/_includes/footer.html
@@ -65,4 +65,5 @@
The preCICE newsletter
+
diff --git a/css/customstyles-precice.css b/css/customstyles-precice.css
index a7c72dff67..27fc166211 100644
--- a/css/customstyles-precice.css
+++ b/css/customstyles-precice.css
@@ -376,3 +376,39 @@ details > summary::after {
details[open] > summary::after {
content: "▲";
}
+
+/* Copy to Clipboard Button Styles */
+div.highlighter-rouge {
+ position: relative;
+}
+
+.copy-code-btn {
+ position: absolute;
+ top: 5px;
+ right: 5px;
+ padding: 4px 8px;
+ font-size: 12px;
+ color: #555;
+ background-color: #f8f9fa;
+ border: 1px solid #ccc;
+ border-radius: 4px;
+ cursor: pointer;
+ opacity: 0;
+ transition: opacity 0.2s, background-color 0.2s, color 0.2s;
+ z-index: 10;
+}
+
+div.highlighter-rouge:hover .copy-code-btn {
+ opacity: 1;
+}
+
+.copy-code-btn:hover {
+ background-color: #e2e6ea;
+ color: #333;
+}
+
+.copy-code-btn.copied {
+ background-color: #28a745;
+ color: white;
+ border-color: #28a745;
+}
diff --git a/js/copy-code.js b/js/copy-code.js
new file mode 100644
index 0000000000..2d8a708505
--- /dev/null
+++ b/js/copy-code.js
@@ -0,0 +1,54 @@
+document.addEventListener('DOMContentLoaded', () => {
+ const codeBlocks = document.querySelectorAll('div.highlighter-rouge');
+
+ codeBlocks.forEach(codeBlock => {
+ const copyButton = document.createElement('button');
+ copyButton.className = 'copy-code-btn';
+ copyButton.innerHTML = ' Copy';
+ copyButton.setAttribute('aria-label', 'Copy code to clipboard');
+
+ codeBlock.appendChild(copyButton);
+
+ copyButton.addEventListener('click', async () => {
+ const code = codeBlock.querySelector('code');
+ if (!code) return;
+
+ try {
+ const textToCopy = code.textContent;
+
+ if (navigator.clipboard && window.isSecureContext) {
+ await navigator.clipboard.writeText(textToCopy);
+ } else {
+ // Fallback for HTTP (non-secure) contexts
+ const textArea = document.createElement("textarea");
+ textArea.value = textToCopy;
+ textArea.style.position = "fixed";
+ textArea.style.left = "-999999px";
+ textArea.style.top = "-999999px";
+ document.body.appendChild(textArea);
+ textArea.focus();
+ textArea.select();
+
+ try {
+ document.execCommand('copy');
+ } catch (err) {
+ console.error('Fallback copy failed', err);
+ }
+ textArea.remove();
+ }
+
+ // Visual feedback
+ const originalHtml = copyButton.innerHTML;
+ copyButton.innerHTML = ' Copied!';
+ copyButton.classList.add('copied');
+
+ setTimeout(() => {
+ copyButton.innerHTML = originalHtml;
+ copyButton.classList.remove('copied');
+ }, 2000);
+ } catch (err) {
+ console.error('Failed to copy text: ', err);
+ }
+ });
+ });
+});