I was looking for a way to add a copy to clipboard button in a code block and found a tutorial from Rob O’Leary.

The code works very well but there is one problem, if we scroll the content of the code block, the button will not always appear in the top right corner.

There are many solutions such as adding a div for this copy button. But I want the easiest and simplest way, so I attached a scroll event listener to the pre element, which adjusts the right offset dynamically to this button.

// Keep button fixed when scrolling horizontally
block.addEventListener("scroll", () => {
    button.style.right = 10 - block.scrollLeft + "px"; // Adjust right offset dynamically
});

Here’s the complete JavaScript code for adding this functionality:

<script>
const copyButtonLabel = "Copy";
let blocks = document.querySelectorAll("pre:has(code)");

blocks.forEach((block) => {
    if (navigator.clipboard) {
        let button = document.createElement("button");
        button.className = "btn btn-secondary btn-sm copy-code";
        button.innerHTML = copyButtonLabel;

        block.style.position = "relative"; // Ensure `pre` is positioned
        block.appendChild(button); // Attach the button inside `pre`

        button.addEventListener("click", async () => {
            await copyCode(block, button);
        });

        // Keep button fixed when scrolling horizontally
        block.addEventListener("scroll", () => {
            button.style.right = 10 - block.scrollLeft + "px"; // Adjust right offset dynamically
        });
    }
});

async function copyCode(block, button) {
    let code = block.querySelector("code");
    let text = code.innerText;
    await navigator.clipboard.writeText(text);

    button.innerText = "Copied!";
    setTimeout(() => {
        button.innerHTML = copyButtonLabel;
    }, 700);
}
</script>

And for the CSS it is as follows, as I use on this blog:

pre {
    background-color: rgba(0, 0, 0, 0.06);
    border: 1px solid rgba(51, 51, 51, 0.1);
    line-height: 1.4;
    margin-bottom: 1.6em;
    max-width: 100%;
    overflow: auto;
    padding: 1.2em;
    font-size: 14px;
    border-radius: 4px;
    color: #000;
}
code {
    color: #000;
    background-color: rgba(0, 0, 0, 0.06);
    border: 1px solid rgba(51, 51, 51, 0.1);
    padding: 4px 8px;
    border-radius: 4px;
    font-size: 14px;
}
pre > code {
    background-color: transparent;
    border: none;
    padding: 0;
    border-radius: 0;
}
pre .copy-code {
    position: absolute;
    top: 10px;
    right: 10px;
    display:none;
}
pre:has(code) {
    position: relative;
}
pre:has(code):hover .copy-code {
    display:block;
}

For the button style, my blog template uses Bootstrap 5 so I just need to add a class into it, see button.className. For the demo you can see it on this blog.

Read also: Add Syntax Highlighting to Blog