<?xml version="1.0" encoding="UTF-8"?><?xml-stylesheet href="/assets/rss.xsl" type="text/xsl"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
>
<channel>
	<title>Sacha Chua - category - css</title>
	<atom:link href="https://sachachua.com/blog/category/css/feed/index.xml" rel="self" type="application/rss+xml" />
	<atom:link href="https://sachachua.com/blog/category/css" rel="alternate" type="text/html" />
	<link>https://sachachua.com/blog/category/css/feed/index.xml</link>
	<description>Emacs, sketches, and life</description>
	<lastBuildDate>Fri, 17 Apr 2026 13:26:41 GMT</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>daily</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>11ty</generator>
  <item>
		<title>Using Javascript to add a "Copy code" link to source code blocks in my blog posts</title>
		<link>https://sachachua.com/blog/2023/01/using-javascript-to-add-a-copy-code-link-to-source-code-blocks-in-my-blog-posts/</link>
		<dc:creator><![CDATA[Sacha Chua]]></dc:creator>
		<pubDate>Sat, 07 Jan 2023 20:32:31 GMT</pubDate>
    <category>css</category>
<category>js</category>
<category>blogging</category>
		<guid isPermaLink="false">https://sachachua.com/blog/2023/01/using-javascript-to-add-a-copy-code-link-to-source-code-blocks-in-my-blog-posts/</guid>
		<description><![CDATA[<p>
I'd like to write about code more often. It's easier for people to try
out ideas if they can copy the code without fiddling with selecting
the text, especially on mobile browsers, so "Copy code" buttons on
source code blocks would be nice. I used <a href="https://www.roboleary.net/2022/01/13/copy-code-to-clipboard-blog.html">this tutorial for adding code buttons</a> as a basis for the following CSS and JS code.
</p>

<p>
First, let's add the buttons with Javascript. I want the buttons to be
visible in the summary line if I'm using the <code>&lt;details /&gt;</code> element. If
not, they can go in the div with the <code>org-src-container</code> class.
</p>

<p>
</p><div class="org-src-container">
<pre class="src src-js"><span class="org-comment-delimiter">/* </span><span class="org-comment">Start of copy code</span><span class="org-comment-delimiter"> */</span>
<span class="org-comment-delimiter">// </span><span class="org-comment">based on https://www.roboleary.net/2022/01/13/copy-code-to-clipboard-blog.html</span>
<span class="org-keyword">const</span> <span class="org-variable-name">copyLabel</span> = <span class="org-string">'Copy code'</span>;

<span class="org-keyword">async</span> <span class="org-keyword">function</span> copyCode(<span class="org-variable-name">block</span>, <span class="org-variable-name">button</span>) {
  <span class="org-keyword">let</span> <span class="org-variable-name">code</span> = block.querySelector(<span class="org-string">'pre.src'</span>);
  <span class="org-keyword">let</span> <span class="org-variable-name">text</span> = code.innerText;
  <span class="org-keyword">await</span> navigator.clipboard.writeText(text);
  button.innerText = <span class="org-string">'Copied'</span>;
  setTimeout(() =&gt; {
    button.innerText = copyLabel;
  }, 500);
}

<span class="org-keyword">function</span> <span class="org-function-name">addCopyCodeButtons</span>() {
  <span class="org-keyword">if</span> (!navigator.clipboard) <span class="org-keyword">return</span>;
  <span class="org-keyword">let</span> <span class="org-variable-name">blocks</span> = document.querySelectorAll(<span class="org-string">'.org-src-container'</span>);
  blocks.forEach((block) =&gt; {
    <span class="org-keyword">let</span> <span class="org-variable-name">button</span> = document.createElement(<span class="org-string">'button'</span>);
    button.innerText = copyLabel;
    button.classList.add(<span class="org-string">'copy-code'</span>);
    <span class="org-keyword">let</span> <span class="org-variable-name">details</span> = block.closest(<span class="org-string">'details'</span>);
    <span class="org-keyword">let</span> <span class="org-variable-name">summary</span> = details &amp;&amp; details.querySelector(<span class="org-string">'summary'</span>);
    <span class="org-keyword">if</span> (summary) {
      summary.appendChild(button);
    } <span class="org-keyword">else</span> {
      block.appendChild(button);
    }
    button.addEventListener(<span class="org-string">'click'</span>, <span class="org-keyword">async</span>() =&gt; {
      <span class="org-keyword">await</span> copyCode(block, button);
    });
    block.setAttribute(<span class="org-string">'tabindex'</span>, 0);
  });
}
document.addEventListener(<span class="org-string">"DOMContentLoaded"</span>, <span class="org-keyword">function</span>(<span class="org-variable-name">event</span>) { 
  addCopyCodeButtons();
});
<span class="org-comment-delimiter">/* </span><span class="org-comment">End of copy code</span><span class="org-comment-delimiter"> */</span>
</pre>
</div>

<p></p>

<p>
Then we style it:
</p>

<p>
</p><div class="org-src-container">
<pre class="src src-css"><span class="org-comment-delimiter">/* </span><span class="org-comment">Start of copy code</span><span class="org-comment-delimiter"> */</span>
<span class="org-css-selector">pre.src</span> { <span class="org-css-property">margin</span>: 0 }
<span class="org-css-selector">.org-src-container</span> {
    <span class="org-css-property">position</span>: relative;
    <span class="org-css-property">margin</span>: 0 0;
    <span class="org-css-property">padding</span>: 1.75rem 0 1.75rem 1rem;
}
<span class="org-css-selector">summary</span> { <span class="org-css-property">position</span>: relative; }
<span class="org-css-selector">summary .org-src-container</span> { <span class="org-css-property">padding</span>: 0 }
<span class="org-css-selector">summary .org-src-container pre.src</span> { <span class="org-css-property">margin</span>: 0 }
<span class="org-css-selector">.org-src-container button.copy-code, summary button.copy-code</span> {
    <span class="org-css-property">position</span>: absolute;
    <span class="org-css-property">top</span>: 0px;
    <span class="org-css-property">right</span>: 0px;
}
<span class="org-comment-delimiter">/* </span><span class="org-comment">End of copy code</span><span class="org-comment-delimiter"> */</span>
</pre>
</div>

<p></p>

<p>
Someday I'll figure out how to make it easier to tangle things to the
post's directory and make the file available for download. In the
meantime, this might be a good start.
</p>

<p>You can <a href="mailto:sacha@sachachua.com?subject=Comment%20on%20https%3A%2F%2Fsachachua.com%2Fblog%2F2023%2F01%2Fusing-javascript-to-add-a-copy-code-link-to-source-code-blocks-in-my-blog-posts%2F&body=Name%20you%20want%20to%20be%20credited%20by%20(if%20any)%3A%20%0AMessage%3A%20%0ACan%20I%20share%20your%20comment%20so%20other%20people%20can%20learn%20from%20it%3F%20Yes%2FNo%0A">e-mail me at sacha@sachachua.com</a>.</p>]]></description>
		</item>
	</channel>
</rss>