Copy *and* Paste? …in this Economy?
Astute visitors to the Eleventy Documentation will notice something new on the code blocks on the site.
This feature been a long time coming and is our first use of Web Awesome on the docs (via the <wa-copy-button> custom element). Take special note of the unparalleled synergy of the Font Awesome icon used by the Web Awesome component used on the Eleventy docs.
- Progressive Enhancement behavior: this is a JavaScript-only feature and has no before/without JavaScript experience. You might call this a JavaScript Web Component.
- Performance-focused:
- This is using a build-time component bundle (read more about Bundling below)
- The JavaScript code for the component only loads when an instance is visible (via
<is-land>)
Usage
Direct from CDN
There are a few ways to use the Copy Button component stock, with the easiest being to load the script directly from the CDN, like so (via jsdelivr):
<script type="module" src="https://cdn.jsdelivr.net/npm/@awesome.me/webawesome@3.0.0/dist-cdn/components/copy-button/copy-button.js"></script>
Or via unpkg:
<script type="module" src="https://unpkg.com/@awesome.me/webawesome@3.0.0/dist-cdn/components/copy-button/copy-button.js"></script>
Bundling
For this implementation we used esbuild to create a focused bundle for the single Web Awesome component (though this esbuild code would work for any JavaScript file).
We went with this method for improved runtime performance and to reduce the number of third-party dependencies on the web site (with a nod to André Jaenisch). You can do the same with the following bit of Eleventy configuration (e.g. in a eleventy.config.js file):
// eleventy.config.js
// don’t forget to `npm install esbuild -D`
import esbuild from "esbuild";
import { fileURLToPath } from "node:url";
async function esbuildToFile(entryPoints, outfile, options = {}) {
return esbuild.build(Object.assign({
entryPoints,
platform: "browser",
format: "esm",
bundle: true,
minify: true,
banner: {
js: `/* via ${entryPoints} */`,
},
outfile,
}, options));
}
async function bundleModuleToFile(modulePath, outfile) {
let sourcefile = fileURLToPath(import.meta.resolve(modulePath));
return esbuildToFile([ sourcefile ], outfile);
}
export default async function(eleventyConfig) {
let outfile = path.join(eleventyConfig.directories.output, "js/copy-button.js");
// This will run once per build/serve/watch
// (not with subsequent builds, save for config file changes)
await bundleModuleToFile("@awesome.me/webawesome/dist/components/copy-button/copy-button.js", outfile);
}
Markdown Code Block Wrappers
This task also served as the impetus for fixes related to wrapper elements around code blocks in Markdown, documented in the previous blog post on this very web site.

