My thoughts on understanding dependencies, and adding a copy button to code blocks on my site Sep 11 2021 Latest Update: Sep 12 2021

I decided to add a new copy button to all of the code blocks on my site. I'll show you how to do the same, but I also want to share my thoughts on adding dependencies to any project.

Currently, it is as easy as importing a new library to add new functionality to any project. It didn't use to be like that—blog posts were as valuable as code. Code used to be simpler, and it was created for a specific scenario. But if you understood how the code worked, you could change it and adapt it to solve your problem.

Currently, importing code is so easy, and understanding the code seems harder. And like water, we take the path of least resistance.

But is the ease of adding dependencies a good trade-off?

The ease of importing libraries

My website is my digital garden. It is as simple as I could make it. The CSS is simple, the JavaScript is also simple, and in my opinion, it works perfectly for what it was created to do. I'm not a fan of the "modern" frontend frameworks. Every few months, when I need to retake a JavaScript project, it feels like starting from scratch. There is some knowledge that can be transferred, but there is so much to refactor.

The problem is not only the re-learning but also the re-setting up of my dev environment.

I don't think it is, in any way, productive.

I much preferred the good old days when you searched for a topic, read a couple of good blog posts, and implemented a solution. I'm not advocating for re-solving old problems. But adding a black box to your dependencies, which in many cases will lower your understanding of your project, is, for me, not a good bargain.

So what is the problem?

The problem is that adding dependencies has become very easy. In the past, adding someone else's code to your codebase took some time. You first had to understand the code and then incorporate it into your codebase. Now the understanding has become harder and the adding easier.

It might seem more pragmatic. In the end, our objective is to solve a problem.

But I would argue that your codebase will become hard to understand without understanding the dependency.

Anyways, I'll try to keep my ranting to a minimum. But I'll give you an example by showing you how I found a good blog post and how I adapted the code in it.

Adding copy to clipboard to my code blocks

After some searching, I came across a few good blog posts that explain how to solve this problem:

As you can see, both articles show a simple way of doing it. But if I copy and paste that code into my blog, it won't work. That is because my code blocks are not rendered the same way as both of those articles. The main idea is to add the buttons to the DOM for every code block and set the event listener to capture the content using a closure.

Note: I'm using the code on the second article.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
function addCopyButtons(clipboard) {
    // 1. Get all the code blocks
    document.querySelectorAll('pre > code').forEach(function (codeBlock) {
        // 2. Create the HTML element that we'll add to the DOM
        var button = document.createElement('button');
        button.className = 'copy-code-button';
        button.type = 'button';
        button.innerText = 'Copy';

        // 3. Extract the text we want to copy
        let block = codeBlock.querySelector('.rouge-code'); 
        let blockStr = block.innerText;


        // 4. Create the event listener and using a closure save the
        // content of the text we want to save and add it to the clipboard
        button.addEventListener('click', function () {
            clipboard.writeText(blockStr).then(function () {
                /* Chrome doesn't seem to blur automatically,
                   leaving the button in a focused state. */
                button.blur();

                button.innerText = 'Copied!';

                setTimeout(function () {
                    button.innerText = 'Copy';
                }, 2000);
            }, function (error) {
                button.innerText = 'Error';
            });
        });

        // 5. Add the button we created with the correct handler
        // To the DOM in the place we want it to be
        var pre = codeBlock.parentNode;
        if (pre.parentNode.classList.contains('highlight')) {
            var highlight = pre.parentNode;
            highlight.parentNode.insertBefore(button, highlight);
        } else {
            pre.parentNode.insertBefore(button, pre);
        }
    });
}

The steps are as follows:

  1. Get all the code blocks by using a selector (this will change in your case depending on your markup)
  2. Create the HTML element that we'll add to the DOM (the button)
  3. Extract the text we want to copy from the code block
  4. Create an event listener, and using a closure, save the content of the text we want to add to the clipboard
  5. Add the button we created with the correct handler to the DOM (above the code block)

If you read the code with the comments, it makes perfect sense. Now you understand what is going on. If you need to adapt it to your website, you won't struggle much. You can easily add more functionality to it. The same happens with the styling. If you give a glance at the CSS, which you can see in the following code block, you'll be able to adapt it to your need:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
.copy-code-button {
    color: #272822;
    background-color: #FFF;
    border-color: #272822;
    border: 2px solid;
    border-radius: 3px 3px 0px 0px;

    /* right-align */
    display: block;
    margin-left: auto;
    margin-right: 0;

    margin-bottom: -2px;
    padding: 3px 8px;
    font-size: 0.8em;
}

.copy-code-button:hover {
    cursor: pointer;
    background-color: #F2F2F2;
}

.copy-code-button:focus {
    /* Avoid an ugly focus outline on click in Chrome,
       but darken the button for accessibility.
       See https://stackoverflow.com/a/25298082/1481479 */
    background-color: #E6E6E6;
    outline: 0;
}

.copy-code-button:active {
    background-color: #D9D9D9;
}

.highlight pre {
    /* Avoid pushing up the copy buttons. */
    margin: 0;
}

That is how good articles/blog posts should be. They guide you, so you understand. Understanding is essential. Once you understand, you can use a similar approach to solve some other problem.

If I package my solution and just told you: "add this import statement to your header", you have gained nothing. This advice is only useful if your goal is to learn. If you are not a developer or a hobbyist that wants to deepen your knowledge, ask for solutions. You don't need to understand how combustion engines work to ride a car. But if this is your profession, stop avoiding understanding.

And that's it for this post. I hope you find it helpful, or at least entertaining.

Conclusion

As with everything in life, balance is key. Don't become a fundamentalist, be practical. See what benefits you the most in the long run. Take the time to understand what code you are bringing into your codebase. And ask yourself, is this making my codebase more complex?

Try to avoid complexity, for complexity's sake.

And also, I encourage you to share your knowledge. I've benefited my whole life from what people share on the Internet, sometimes for free other times for a small fee. That is one of the reasons for this site, to give back. I hope it helps. And enjoy the new button on my code blocks!

References


** If you want to check what else I'm currently doing, be sure to follow me on twitter @rderik or subscribe to the newsletter. If you want to send me a direct message, you can send it to derik@rderik.com.