Getting Started
Note
This post is meant to be a way to create your own code formatter, however, this website does not utilize the codeblocks shown and relies on Expressive Code instead.
You want to first install Lit
into your current Astro project. You can do this with
Creating JS files
In your components folder, create a new folder named copy-code
(or whatever name you prefer.) Create these files in the folder you just created and paste the following code:
import { LitElement, html, css } from "lit" ;
export const copyIcon = html `<svg
xmlns="http://www.w3.org/2000/svg"
<path d="M0 0h24v24H0z" fill="none" />
d="M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm3 4H8c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v14z"
export const checkIcon = html `<svg
xmlns="http://www.w3.org/2000/svg"
<path d="M0 0h24v24H0z" fill="none" />
<path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z" />
export class CopyCodeButton extends LitElement {
@keyframes animateScale {
animation: animateScale 0.5s ease;
static get properties () {
_isCopied: { type: Boolean },
const pre = this .parentElement;
let code = pre. querySelector ( "code" );
const range = document. createRange ();
window. getSelection (). removeAllRanges ();
window. getSelection (). addRange (range);
// check if the browser supports clipboard API
if ( ! navigator.clipboard) {
// if not use the old commandExec() way
document. execCommand ( "copy" );
navigator.clipboard. writeText (range. toString ());
window. getSelection (). removeAllRanges ();
const button = this .shadowRoot. querySelector ( "button" );
button.classList. add ( "clicked" );
button.classList. remove ( "clicked" );
<button @click=${ this . copyCode }>
${ this . _isCopied ? checkIcon : copyIcon }
customElements. define ( "copy-code-button" , CopyCodeButton);
let blocks = document. querySelectorAll ( "pre" );
blocks. forEach (( block ) => {
let codeElement = block. querySelector ( "code" );
let containerDiv = document. createElement ( "div" );
containerDiv.classList. add ( "code-container" );
containerDiv. appendChild (codeElement);
block. appendChild (containerDiv);
let button = document. createElement ( "copy-code-button" );
containerDiv. appendChild (button); // Append button to the containerDiv, not block
pre [ class *= "language-" ] {
pre code ::-webkit-scrollbar-corner {
background-color : transparent ;
pre code ::-webkit-scrollbar {
background-color : transparent ;
pre code ::-webkit-scrollbar-track {
background-color : transparent ;
pre code .dark::-webkit-scrollbar-thumb {
background-color : #363636 ;
pre code .dark::-webkit-scrollbar-thumb:hover {
pre code ::-webkit-scrollbar-thumb {
background-color : #c1c1c1 ;
pre code ::-webkit-scrollbar-thumb:hover {
background-color : #a0a0a0 ;
scrollbar-color : #363636 transparent ;
pre code .dark::-moz-scrollbar-thumb {
background-color : #363636 ;
pre code .dark::-moz-scrollbar-thumb:hover {
pre code ::-moz-scrollbar {
background-color : transparent ;
pre code ::-moz-scrollbar-track {
background-color : transparent ;
pre code ::-moz-scrollbar-thumb {
background-color : #c1c1c1 ;
pre code ::-moz-scrollbar-thumb:hover {
background-color : #a0a0a0 ;
-ms-overflow-style : none ;
overflow : -moz-scrollbars-none ;
-ms-overflow-style : auto ;
In your layouts folder, go to the main layout and add these lines of code:
import "../styles/globals.scss" ;
import "@/components/copy-code/copy-code-button.js" ;
import "@/components/copy-code/create-copy-buttons.js" ;
And you’re basically all set! Just refresh the page and a copy button should appear on all your code blocks!
Acknowledgements:
This guide was inspired by Jaydan Urwin . However, his code had a couple of bugs with how the copy button was positioned (during overflow). This code fixes that as well as provide scrollbars when an overflow occurs.