Copy code in Astro to clipboard


This JavaScript was intended specifically for use with ASTRO, but with minimal effort the code could probably be modified to work with any Markdown-generated HTML.

Copy Asto-displayed fenced code to the clipboard

The JavaScript below adds a link in the code block to copy it to the clipboard, as shown below:


Add the JavaScript below to your Astro project’s client-side JavaScript.

const copyToClipboard = (str) => {
  if (navigator && navigator.clipboard && navigator.clipboard.writeText)
    return navigator.clipboard.writeText(str);
  return Promise.reject("The Clipboard API is not available.");

const preTags = document.querySelectorAll("pre");
let counter = 1;
preTags.forEach((tag) => {
  const codeId = `id-${counter++}`;
  tag.setAttribute("data-code-id", codeId);
  const insertCodeButton = `
    <small class="copy-code-label">    
        <a data-code-id="${codeId}"
           title="Ctrl/Click to copy with line numbers" 
           class="copy-code-button" href=#>
           <i class="copy-icon fa-light fa-copy"></i> <span class="copy-text">copy</span>
  tag.insertAdjacentHTML("beforebegin", insertCodeButton);

const copyButtons = document.querySelectorAll(".copy-code-button");
copyButtons.forEach((button) => {
  button.addEventListener("click", (e) => {

    const codeId = e.currentTarget.getAttribute("data-code-id");
    const preTag = document.querySelector(`pre[data-code-id="${codeId}"]`);
    const codeTag = preTag.firstChild;

    const faIconEl = button.querySelector(".copy-icon");
    const textEl = e.currentTarget.querySelector('span[class="copy-text"]');

    textEl.innerText = "copied";
    faIconEl.classList.remove("fa-light", "fa-copy");
    faIconEl.classList.add("fa-solid", "fa-thumbs-up");

    let source;
    if (preTag.hasAttribute("data-source"))
      source = preTag.getAttribute("data-source");
    else source = codeTag.innerText;


    setTimeout(() => {
      textEl.innerText = "copy";
      faIconEl.classList.remove("fa-solid", "fa-thumbs-up");
      faIconEl.classList.add("fa-light", "fa-copy");
    }, 1000);

Add these three CSS selectors to your Astro project’s global CSS:

.copy-code-label {
  display: flex;
  justify-content: flex-end;
  margin-bottom: 5px;
  position: relative;
.copy-code-label a {
  color: gray;
  position: absolute;
  top: 16px;
  right: 10px;
  text-decoration: none;

.copy-code-label a:after {
  content: "";
  height: 1px;
  background: gray;
  display: block;

This JavaScript uses FontAwesome icons.

Show line numbers in Asto-displayed fenced code

Use the JavaScript to add line numbers to fenced code blocks in Astro. To assign line numbers to a fenced code block, add a <div class="number-code below"></div> just above the markdown fence, leaving one blank line between the div` tag and the fence (as shown below).

<div class="number-code below"></div

    ... code to display here

Add the Javascript addLineNumbers function to the Astro app’s client-side JavaScript.

const addLineNumbers = () => {
  const snippetInstances = document.querySelectorAll(
    "div.number-code-below + small +  pre > code"

  snippetInstances.forEach((snippetInstance) => {

    const lines = snippetInstance.querySelectorAll("span.line");

    let leadingSpacesCount = 2;
    if (lines.length > 99) leadingSpacesCount = 3;
    if (lines.length < 10) leadingSpacesCount = 1;

    let counter = 1;
    lines.forEach((line) => {
      const lineNo = counter.toString().padStart(leadingSpacesCount, " ");
        `<span style="color: lightskyblue; border-right: 1px lightskyblue solid;padding-right: .2rem;margin-right: .5rem; ">${lineNo}</span>`

Call the addLineNumbers() function after the page loads.