From fc6c972a0e27cdd98e23477702b3ab2be2dd0d2e Mon Sep 17 00:00:00 2001 From: shubham Date: Sun, 23 Mar 2025 19:49:20 +0530 Subject: [PATCH 01/13] test: copy code btn --- _includes/head.html | 1 + css/style.css | 23 +++++++++++++++++++++++ js/copycode.js | 36 ++++++++++++++++++++++++++++++++++++ 3 files changed, 60 insertions(+) create mode 100644 js/copycode.js diff --git a/_includes/head.html b/_includes/head.html index 3b750235a3..e4562076ac 100644 --- a/_includes/head.html +++ b/_includes/head.html @@ -46,6 +46,7 @@ + diff --git a/css/style.css b/css/style.css index 857a252dba..d96a14bdac 100644 --- a/css/style.css +++ b/css/style.css @@ -365,6 +365,29 @@ pre code { padding: 0; } +pre:has(code) { + position: relative; + + &:is(:hover, :focus) { + button { + display: block; + } + } +} + +pre:has(code) button{ + position: absolute; + top: 5px; + right: 5px; + padding: 5px; + border-radius: 5px; + background-color: var(--code-bg); + color: var(--card-fg); + border: none; + outline: solid 2px var(--border); + display: none; +} + /* top button */ .scroll #top { diff --git a/js/copycode.js b/js/copycode.js new file mode 100644 index 0000000000..2ebea69938 --- /dev/null +++ b/js/copycode.js @@ -0,0 +1,36 @@ +const blocks = document.querySelectorAll("pre:has(code)"); +const copyButtonLabel = "Copy Code"; + + +blocks.forEach((block) => { + // only add button if browser supports Clipboard API + if (navigator.clipboard) { + const button = document.createElement("button"); + button.innerText = copyButtonLabel; + block.appendChild(button); + block.setAttribute("tabindex", 0); //add keyboard a11y for pre + + button.addEventListener("click", async () => { + await copyCode(block, button); + }); + } +}); + +async function copyCode(block, button) { + const code = block.querySelector("code"); + const text = code.innerText; + + await navigator.clipboard.writeText(text); + + // visual feedback that task is completed + button.innerText = "✔ Copied!"; + button.setAttribute("aria-live", "polite"); // screen reader will announce text is copied to clipboard + + const timer = setTimeout(() => { + button.innerText = copyButtonLabel; + }, 1000); + + // remove previous timer on multiple clicks + button.dataset.timerId && clearTimeout(button.dataset.timerId); + button.dataset.timerId = timer; + }; \ No newline at end of file From f045d2fe963278bde7ba16e57f1329c51c2c8c3f Mon Sep 17 00:00:00 2001 From: shubham Date: Mon, 24 Mar 2025 18:31:44 +0530 Subject: [PATCH 02/13] add copy btn svg --- images/copy-btn.svg | 1 + 1 file changed, 1 insertion(+) create mode 100644 images/copy-btn.svg diff --git a/images/copy-btn.svg b/images/copy-btn.svg new file mode 100644 index 0000000000..d44b4a72f1 --- /dev/null +++ b/images/copy-btn.svg @@ -0,0 +1 @@ + \ No newline at end of file From fd12e5491fb5d282f18fb7dcb33d8e6dd11ec264 Mon Sep 17 00:00:00 2001 From: shubham Date: Mon, 24 Mar 2025 18:32:43 +0530 Subject: [PATCH 03/13] add copy code btn --- css/style.css | 25 ++++++++++++++++++++----- js/copycode.js | 46 ++++++++++++++++++++++++---------------------- 2 files changed, 44 insertions(+), 27 deletions(-) diff --git a/css/style.css b/css/style.css index de783b1085..ee6f6ffac7 100644 --- a/css/style.css +++ b/css/style.css @@ -360,19 +360,34 @@ pre:has(code) { display: block; } } + + &:focus-within button { + display: block; + } } pre:has(code) button{ position: absolute; top: 5px; right: 5px; - padding: 5px; - border-radius: 5px; - background-color: var(--code-bg); - color: var(--card-fg); + background-color: var(--card-fg); + mask-image: url("../images/copy-btn.svg"); + mask-size: 1.5rem; + mask-repeat: no-repeat; border: none; - outline: solid 2px var(--border); display: none; + width: 1.5rem; + height: 1.5rem; + + @media all and (max-width: 370px) { + width: 1rem; + height: 1rem; + mask-size: 1rem; + } +} + +pre:has(code) button.copied { + background-color: var(--supported-fg); } /* top button */ diff --git a/js/copycode.js b/js/copycode.js index 2ebea69938..610297db7b 100644 --- a/js/copycode.js +++ b/js/copycode.js @@ -1,19 +1,19 @@ -const blocks = document.querySelectorAll("pre:has(code)"); -const copyButtonLabel = "Copy Code"; +const codeBlocks = document.querySelectorAll("pre:has(code)"); - -blocks.forEach((block) => { +codeBlocks.forEach((block) => { // only add button if browser supports Clipboard API - if (navigator.clipboard) { - const button = document.createElement("button"); - button.innerText = copyButtonLabel; - block.appendChild(button); - block.setAttribute("tabindex", 0); //add keyboard a11y for pre + if (!navigator.clipboard) return; + + const button = document.createElement("button"); + button.setAttribute("title", "copy code"); + button.setAttribute("aria-label","copy code"); + block.appendChild(button); + block.setAttribute("tabindex", 0); //add keyboard a11y for
 
+
+  button.addEventListener("click", async () => {
+    await copyCode(block, button);
+  });
 
-    button.addEventListener("click", async () => {
-      await copyCode(block, button);
-    });
-  }
 });
 
 async function copyCode(block, button) {
@@ -21,16 +21,18 @@ async function copyCode(block, button) {
     const text = code.innerText;
   
     await navigator.clipboard.writeText(text);
-  
-    // visual feedback that task is completed
-    button.innerText = "✔ Copied!";
-    button.setAttribute("aria-live", "polite"); // screen reader will  announce text is copied to clipboard
-  
+    // screen reader will  announce text is copied to clipboard
+    button.setAttribute("aria-label","copied!");
+    button.setAttribute("aria-live", "polite"); 
+    button.classList.add("copied");
+
+    // remove previous timer on multiple clicks (data-timer-id)
+    if (button.dataset.timerId) clearTimeout(button.dataset.timerId);
+    
     const timer = setTimeout(() => {
-      button.innerText = copyButtonLabel;
+      button.classList.remove("copied");
+      button.setAttribute("aria-label","copy code");
     }, 1000);
 
-    // remove previous timer on multiple clicks
-    button.dataset.timerId && clearTimeout(button.dataset.timerId); 
     button.dataset.timerId = timer;
-  };
\ No newline at end of file
+  };

From 21067f43398ef0878ddaea3b77cc1fc118448ae3 Mon Sep 17 00:00:00 2001
From: shubham 
Date: Wed, 26 Mar 2025 11:33:34 +0530
Subject: [PATCH 04/13] fix: keyboard a11y and improve design

---
 css/style.css | 42 +++++++++++++++++++++++++++++++++---------
 1 file changed, 33 insertions(+), 9 deletions(-)

diff --git a/css/style.css b/css/style.css
index ee6f6ffac7..2c87821f00 100644
--- a/css/style.css
+++ b/css/style.css
@@ -346,6 +346,11 @@ pre {
   border-radius: 3px;
   border: 1px solid #ddd;
   background-color: var(--code-bg);
+/* keyboard focus offset improve visibility */
+  &:focus {
+    outline-offset: 2px;
+    outline: 2px solid var(--hover-border);
+  }
 }
 
 pre code {
@@ -357,37 +362,56 @@ pre:has(code) {
 
   &:is(:hover, :focus) {
     button {
-      display: block;
+      display: flex;
     }
   }
 
   &:focus-within button {
-    display: block;
+    display: flex;
   }
 }
 
-pre:has(code) button{
+pre:has(code) button {
   position: absolute;
   top: 5px;
   right: 5px;
+  border: none;
+  display: none;
+  cursor: pointer;
+  background-color: inherit;
+  padding: 2px;
+  border-radius: 5px;
+
+  &::after {
+  content: "";
   background-color: var(--card-fg);
   mask-image: url("../images/copy-btn.svg");
   mask-size: 1.5rem;
   mask-repeat: no-repeat;
-  border: none;
-  display: none;
   width: 1.5rem;
   height: 1.5rem;
+  }
+
+  &:is(:hover, :focus) {
+    background-color: var(--hover-bg);
+    outline: 2px solid var(--hover-border);
+  }
 
   @media all and (max-width: 370px) { 
-    width: 1rem;
-    height: 1rem;
-    mask-size: 1rem;
+    padding: 1px;
+    &::after {
+      mask-size: 1rem;
+      width: 1rem;
+      height: 1rem;
+    }
   }
 }
 
 pre:has(code) button.copied {
-  background-color: var(--supported-fg);
+  outline-color: var(--supported-fg);
+  &::after { 
+    background-color: var(--supported-fg);
+  }
 }
 
 /* top button */

From f15c2e9287783f0e2094b9ed49ad25d75fda297d Mon Sep 17 00:00:00 2001
From: shubham 
Date: Wed, 26 Mar 2025 12:34:56 +0530
Subject: [PATCH 05/13] show "copied !" text on the copy btn

---
 css/style.css  | 35 +++++++++++++++++++++++++++++++----
 js/copycode.js |  8 ++++----
 2 files changed, 35 insertions(+), 8 deletions(-)

diff --git a/css/style.css b/css/style.css
index 2c87821f00..a8596acd3f 100644
--- a/css/style.css
+++ b/css/style.css
@@ -347,9 +347,12 @@ pre {
   border: 1px solid #ddd;
   background-color: var(--code-bg);
 /* keyboard focus offset improve visibility */
-  &:focus {
-    outline-offset: 2px;
-    outline: 2px solid var(--hover-border);
+/* focus on desktop */
+  @media all and (min-width: 1010px) { 
+    &:focus {
+      outline-offset: 2px;
+      outline: 2px solid var(--hover-border);
+    }
   }
 }
 
@@ -365,7 +368,7 @@ pre:has(code) {
       display: flex;
     }
   }
-
+  /* focus copy btn by keyboard */
   &:focus-within button {
     display: flex;
   }
@@ -399,6 +402,7 @@ pre:has(code) button {
 
   @media all and (max-width: 370px) { 
     padding: 1px;
+
     &::after {
       mask-size: 1rem;
       width: 1rem;
@@ -409,9 +413,32 @@ pre:has(code) button {
 
 pre:has(code) button.copied {
   outline-color: var(--supported-fg);
+
   &::after { 
     background-color: var(--supported-fg);
   }
+  
+  &::before {
+    font-size: 0.85rem;
+    position: absolute;
+    left: -58px;
+    content: "copied !";
+    width: fit-content;
+    height: fit-content;
+    padding: 4px;
+    border-radius: 2px;
+    color: var(--card-fg);
+    background-color: var(--card-bg);
+    outline: 1px solid var(--hover-border);
+  }
+
+  @media all and (max-width: 400px) { 
+    &::before {
+      left: -50px;
+      font-size: 0.7rem;
+      padding: 3px;
+    }
+  }
 }
 
 /* top button */
diff --git a/js/copycode.js b/js/copycode.js
index 610297db7b..dde60c414f 100644
--- a/js/copycode.js
+++ b/js/copycode.js
@@ -6,7 +6,7 @@ codeBlocks.forEach((block) => {
 
   const button = document.createElement("button");
   button.setAttribute("title", "copy code");
-  button.setAttribute("aria-label","copy code");
+  button.setAttribute("aria-label","click to copy code");
   block.appendChild(button);
   block.setAttribute("tabindex", 0); //add keyboard a11y for 
 
 
@@ -22,8 +22,8 @@ async function copyCode(block, button) {
   
     await navigator.clipboard.writeText(text);
     // screen reader will  announce text is copied to clipboard
-    button.setAttribute("aria-label","copied!");
-    button.setAttribute("aria-live", "polite"); 
+    button.setAttribute("aria-live", "polite");
+    button.setAttribute("aria-label","code is copied!"); 
     button.classList.add("copied");
 
     // remove previous timer on multiple clicks (data-timer-id)
@@ -31,7 +31,7 @@ async function copyCode(block, button) {
     
     const timer = setTimeout(() => {
       button.classList.remove("copied");
-      button.setAttribute("aria-label","copy code");
+      button.setAttribute("aria-label","click to copy code");
     }, 1000);
 
     button.dataset.timerId = timer;

From 44b08f3db55e585c9cb5cd82b558b1ef61952138 Mon Sep 17 00:00:00 2001
From: shubham oulkar <91728992+ShubhamOulkar@users.noreply.github.com>
Date: Wed, 26 Mar 2025 12:48:04 +0530
Subject: [PATCH 06/13] remove space in copied text

---
 css/style.css | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/css/style.css b/css/style.css
index a8596acd3f..ab793f7901 100644
--- a/css/style.css
+++ b/css/style.css
@@ -422,7 +422,8 @@ pre:has(code) button.copied {
     font-size: 0.85rem;
     position: absolute;
     left: -58px;
-    content: "copied !";
+    content: "copied!";
+
     width: fit-content;
     height: fit-content;
     padding: 4px;

From bbc8743a4aed777542923f9f977197edc5b78a94 Mon Sep 17 00:00:00 2001
From: shubham oulkar <91728992+ShubhamOulkar@users.noreply.github.com>
Date: Wed, 26 Mar 2025 17:26:28 +0530
Subject: [PATCH 07/13] Remove text shift

---
 css/style.css | 1 +
 1 file changed, 1 insertion(+)

diff --git a/css/style.css b/css/style.css
index ab793f7901..2927451139 100644
--- a/css/style.css
+++ b/css/style.css
@@ -379,6 +379,7 @@ pre:has(code) button {
   top: 5px;
   right: 5px;
   border: none;
+  z-index: 100;
   display: none;
   cursor: pointer;
   background-color: inherit;

From 04fdc30ffc1f4c3969b22d3784c2fe757bc34654 Mon Sep 17 00:00:00 2001
From: shubham 
Date: Mon, 7 Apr 2025 02:34:42 +0530
Subject: [PATCH 08/13] handle failed copy code

---
 css/style.css  | 33 +++++++++++++++++++++++++++++++-
 js/copycode.js | 51 ++++++++++++++++++++++++++++++++++----------------
 2 files changed, 67 insertions(+), 17 deletions(-)

diff --git a/css/style.css b/css/style.css
index 2927451139..b43fc7eab0 100644
--- a/css/style.css
+++ b/css/style.css
@@ -431,7 +431,38 @@ pre:has(code) button.copied {
     border-radius: 2px;
     color: var(--card-fg);
     background-color: var(--card-bg);
-    outline: 1px solid var(--hover-border);
+    outline: 1px solid var(--supported-fg);
+  }
+
+  @media all and (max-width: 400px) { 
+    &::before {
+      left: -50px;
+      font-size: 0.7rem;
+      padding: 3px;
+    }
+  }
+}
+
+pre:has(code) button.failed {
+  outline-color: var(--eol-fg);
+
+  &::after { 
+    background-color: var(--eol-fg);
+  }
+  
+  &::before {
+    font-size: 0.85rem;
+    position: absolute;
+    left: -58px;
+    content: "failed!";
+
+    width: fit-content;
+    height: fit-content;
+    padding: 4px;
+    border-radius: 2px;
+    color: var(--card-fg);
+    background-color: var(--card-bg);
+    outline: 1px solid var(--eol-fg);
   }
 
   @media all and (max-width: 400px) { 
diff --git a/js/copycode.js b/js/copycode.js
index dde60c414f..340506d9b2 100644
--- a/js/copycode.js
+++ b/js/copycode.js
@@ -19,20 +19,39 @@ codeBlocks.forEach((block) => {
 async function copyCode(block, button) {
     const code = block.querySelector("code");
     const text = code.innerText;
-  
-    await navigator.clipboard.writeText(text);
-    // screen reader will  announce text is copied to clipboard
-    button.setAttribute("aria-live", "polite");
-    button.setAttribute("aria-label","code is copied!"); 
-    button.classList.add("copied");
-
-    // remove previous timer on multiple clicks (data-timer-id)
-    if (button.dataset.timerId) clearTimeout(button.dataset.timerId);
-    
-    const timer = setTimeout(() => {
-      button.classList.remove("copied");
-      button.setAttribute("aria-label","click to copy code");
-    }, 1000);
-
-    button.dataset.timerId = timer;
+
+    try {
+      // success UI update
+      await navigator.clipboard.writeText(text);
+      // screen reader will  announce text is copied to clipboard
+      button.setAttribute("aria-live", "polite");
+      button.setAttribute("aria-label","code is copied!"); 
+      button.classList.add("copied");
+
+      // remove previous timer on multiple clicks (data-timer-id)
+      if (button.dataset.timerId) clearTimeout(button.dataset.timerId);
+      
+      const timer = setTimeout(() => {
+        button.classList.remove("copied");
+        button.setAttribute("aria-label","click to copy code");
+      }, 1000);
+
+      button.dataset.timerId = timer;
+    }catch{
+      //  failed UI update
+      // screen reader will  announce text is copied to clipboard
+      button.setAttribute("aria-live", "polite");
+      button.setAttribute("aria-label","failed!"); 
+      button.classList.add("failed");
+
+      // remove previous timer on multiple clicks (data-timer-id)
+      if (button.dataset.timerId) clearTimeout(button.dataset.timerId);
+      
+      const timer = setTimeout(() => {
+        button.classList.remove("failed");
+        button.setAttribute("aria-label","click to copy code");
+      }, 100000);
+
+      button.dataset.timerId = timer;
+    }
   };

From 784571ef27b8a072c098a5f445aec0f6d63aa936 Mon Sep 17 00:00:00 2001
From: shubham oulkar <91728992+ShubhamOulkar@users.noreply.github.com>
Date: Mon, 7 Apr 2025 17:52:21 +0530
Subject: [PATCH 09/13] Minimize delay

---
 js/copycode.js | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/js/copycode.js b/js/copycode.js
index 340506d9b2..3ca9921b05 100644
--- a/js/copycode.js
+++ b/js/copycode.js
@@ -50,7 +50,8 @@ async function copyCode(block, button) {
       const timer = setTimeout(() => {
         button.classList.remove("failed");
         button.setAttribute("aria-label","click to copy code");
-      }, 100000);
+      }, 1000);
+
 
       button.dataset.timerId = timer;
     }

From 849bfacbfc66941d769b4f36892b2391227530d1 Mon Sep 17 00:00:00 2001
From: shubham oulkar <91728992+ShubhamOulkar@users.noreply.github.com>
Date: Thu, 17 Apr 2025 09:34:12 +0000
Subject: [PATCH 10/13] remove outline on code blocks

---
 css/style.css | 9 +++------
 1 file changed, 3 insertions(+), 6 deletions(-)

diff --git a/css/style.css b/css/style.css
index 73017e8a3b..145765e5e5 100644
--- a/css/style.css
+++ b/css/style.css
@@ -344,16 +344,13 @@ code {
 pre {
   padding: 16px;
   border-radius: 3px;
-  border: 1px solid #ddd;
+  border: 1px solid var(--border);
   background-color: var(--code-bg);
 /* keyboard focus offset improve visibility */
-/* focus on desktop */
-  @media all and (min-width: 1010px) { 
     &:focus {
-      outline-offset: 2px;
-      outline: 2px solid var(--hover-border);
+      border-width: 2px;
+      border-color: var(--hover-border);
     }
-  }
 }
 
 pre code {

From bcbe344e4b8574d087a6a894d5a6d846b47bc873 Mon Sep 17 00:00:00 2001
From: shubham oulkar <91728992+ShubhamOulkar@users.noreply.github.com>
Date: Sun, 20 Apr 2025 12:49:47 +0000
Subject: [PATCH 11/13] refactor copycode.js

---
 js/copycode.js | 90 +++++++++++++++++++++++++-------------------------
 1 file changed, 45 insertions(+), 45 deletions(-)

diff --git a/js/copycode.js b/js/copycode.js
index 3ca9921b05..859af39045 100644
--- a/js/copycode.js
+++ b/js/copycode.js
@@ -1,58 +1,58 @@
 const codeBlocks = document.querySelectorAll("pre:has(code)");
 
 codeBlocks.forEach((block) => {
-  // only add button if browser supports Clipboard API
+  // Only add button if browser supports Clipboard API
   if (!navigator.clipboard) return;
 
-  const button = document.createElement("button");
-  button.setAttribute("title", "copy code");
-  button.setAttribute("aria-label","click to copy code");
+  const button = createCopyButton();
   block.appendChild(button);
-  block.setAttribute("tabindex", 0); //add keyboard a11y for 
 
+  block.setAttribute("tabindex", 0); // Add keyboard a11y for 

 
   button.addEventListener("click", async () => {
     await copyCode(block, button);
   });
-
 });
 
+function createCopyButton() {
+  const button = document.createElement("button");
+  setButtonAttributes(button, {
+    type: "button", // button doesn't act as a submit button
+    title: "copy code",
+    "aria-label": "click to copy code",
+  });
+  return button;
+}
+
+function setButtonAttributes(button, attributes) {
+  for (const [key, value] of Object.entries(attributes)) {
+    button.setAttribute(key, value);
+  }
+}
+
 async function copyCode(block, button) {
-    const code = block.querySelector("code");
-    const text = code.innerText;
-
-    try {
-      // success UI update
-      await navigator.clipboard.writeText(text);
-      // screen reader will  announce text is copied to clipboard
-      button.setAttribute("aria-live", "polite");
-      button.setAttribute("aria-label","code is copied!"); 
-      button.classList.add("copied");
-
-      // remove previous timer on multiple clicks (data-timer-id)
-      if (button.dataset.timerId) clearTimeout(button.dataset.timerId);
-      
-      const timer = setTimeout(() => {
-        button.classList.remove("copied");
-        button.setAttribute("aria-label","click to copy code");
-      }, 1000);
-
-      button.dataset.timerId = timer;
-    }catch{
-      //  failed UI update
-      // screen reader will  announce text is copied to clipboard
-      button.setAttribute("aria-live", "polite");
-      button.setAttribute("aria-label","failed!"); 
-      button.classList.add("failed");
-
-      // remove previous timer on multiple clicks (data-timer-id)
-      if (button.dataset.timerId) clearTimeout(button.dataset.timerId);
-      
-      const timer = setTimeout(() => {
-        button.classList.remove("failed");
-        button.setAttribute("aria-label","click to copy code");
-      }, 1000);
-
-
-      button.dataset.timerId = timer;
-    }
-  };
+  const code = block.querySelector("code");
+  const text = code.innerText;
+
+  try {
+    await navigator.clipboard.writeText(text);
+    updateButtonState(button, "copied", "code is copied!");
+  } catch {
+    updateButtonState(button, "failed", "failed!");
+  }
+}
+
+function updateButtonState(button, statusClass, ariaLabel) {
+  button.setAttribute("aria-live", "polite");
+  button.setAttribute("aria-label", ariaLabel);
+  button.classList.add(statusClass);
+
+  // Clear any existing timer
+  if (button.dataset.timerId) clearTimeout(button.dataset.timerId);
+
+  const timer = setTimeout(() => {
+    button.classList.remove(statusClass);
+    button.setAttribute("aria-label", "click to copy code");
+  }, 1000);
+
+  button.dataset.timerId = timer;
+}

From a21869acd14f1d339350696d70a401e139f2eb24 Mon Sep 17 00:00:00 2001
From: shubham oulkar <91728992+ShubhamOulkar@users.noreply.github.com>
Date: Tue, 22 Apr 2025 07:59:45 +0530
Subject: [PATCH 12/13] Remove border width

Co-authored-by: Sebastian Beltran 
---
 css/style.css | 1 -
 1 file changed, 1 deletion(-)

diff --git a/css/style.css b/css/style.css
index 145765e5e5..46de8e963e 100644
--- a/css/style.css
+++ b/css/style.css
@@ -348,7 +348,6 @@ pre {
   background-color: var(--code-bg);
 /* keyboard focus offset improve visibility */
     &:focus {
-      border-width: 2px;
       border-color: var(--hover-border);
     }
 }

From 38d082adc9fbd5ed0c4490f4c9200fd8b5f88396 Mon Sep 17 00:00:00 2001
From: shubham oulkar <91728992+ShubhamOulkar@users.noreply.github.com>
Date: Tue, 22 Apr 2025 08:14:58 +0530
Subject: [PATCH 13/13] Convert timerId into a Number()

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
---
 js/copycode.js | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/js/copycode.js b/js/copycode.js
index 859af39045..d95a73f05d 100644
--- a/js/copycode.js
+++ b/js/copycode.js
@@ -47,8 +47,7 @@ function updateButtonState(button, statusClass, ariaLabel) {
   button.classList.add(statusClass);
 
   // Clear any existing timer
-  if (button.dataset.timerId) clearTimeout(button.dataset.timerId);
-
+  if (button.dataset.timerId) clearTimeout(Number(button.dataset.timerId));
   const timer = setTimeout(() => {
     button.classList.remove(statusClass);
     button.setAttribute("aria-label", "click to copy code");