Recently I was creating a new repo on GitHub, a pretty common action for most of us now-a-days. When I noticed a feature which I use everytime but had never given much thought to, the copy to clipboard button.

This is a really useful feature, as I said a second ago, I literally use it everytime. Another great example of this can be found on the Bootstrap site. Each code example has a copy button in the top right corner allowing developers to copy the sample code straight to their clipboard.

I thought this would be a cool little feature to be able to use in Blazor applications so thought I would do a bit of investigation and see how it could be replicated.

In this post I’m going to show you how to create a simple copy to clipboard feature for Blazor apps. We’re going to start by looking at the available APIs we can use for this functionality. From there we are going to create two solutions, one for short amounts of text, replicating the GitHub example above. The other for larger amounts of text, replicating the functionality from the Bootstrap docs.

Choosing the API

The first thing to understand is that we can’t create the feature using C# code alone, we’re going to have to use some JavaScript interop to achieve our goal. There are two API options available to us, Document.execCommand and Clipboard.

Document.execCommand

Historically, clipboard operations have been achieved using execCommand. A quick google of “copy to clipboard in JavaScript” will bring up numerous examples using this API. execCommand is also well supported across the different browsers, a quick check on caniuse.com shows lots of green (95.63%).

However, there is a rather large issue with this API. It’s been marked obsolete.

The good news is there’s a new API which supersedes it called the Clipboard API.

Clipboard API

The new Clipboard API has the ability to read and write to the clipboard both syncronously and asyncronously, as well as integrating with the Permissions API to ensure the user has given permission to do so.

The API breaks down into 2 interfaces, [Clipboard](https://developer.mozilla.org/en-US/docs/Web/API/Clipboard) and [ClipboardEvent](https://developer.mozilla.org/en-US/docs/Web/API/ClipboardEvent). The ClipboardEvent interface gives us access to information about the modification of the clipboard by events such as cut, copy and paste. It’s good to know this is here but the more intestesting stuff is in the Clipboard interface.

The Clipboard interface provides us the functions to interact with the clipboard in our applications and contains the following 4 functions (from the MDN docs):

  • **read()**Requests arbitrary data (such as images) from the clipboard, returning a Promise. When the data has been retrieved, the promise is resolved with a DataTransfer object that provides the data.
  • **readText()**Requests text from the system clipboard; returns a Promise which is resolved with a DOMString containing the clipboard’s text once it’s available.
  • **write()**Writes arbitrary data to the system clipboard. This asynchronous operation signals that it’s finished by resolving the returned Promise.
  • **writeText()**Writes text to the system clipboard, returning a Promise which is resolved once the text is fully copied into the clipboard.

The adoption of this new API isn’t anywhere near as widespread as the old execCommand. The function we’re interested in is writeText has 71.11% adoption according to caniuse.

However, the browsers that don’t support this also don’t support Blazor, so that makes things simple. Based on all the information I decided to go with the new clipboard API for this functionality.

Solution 1: Replicating GitHubs copy to clipboard

In this first solution we’re going to replicate the funcationality from GitHub. This is ideal for any small, single line amounts of text you want to allow users to copy to their clipboards.

First create a component call CopyToClipboard with the following code.

Note: I’m doing this using the standard Blazor project template which has Bootstrap included. So for styling, I’m just using classes from that and some inline styles where needed.

@inject IJSRuntime JSRuntime

<div class="form-inline">
    <input class="form-control" readonly type="text" value="@Text" />
    <button type="button" class="btn btn-primary" @onclick="CopyTextToClipboard">Copy</button>
</div>

@code {    
    [Parameter] public string Text { get; set; }

    private async Task CopyTextToClipboard()
    {
        await JSRuntime.InvokeVoidAsync("clipboardCopy.copyText", Text);
    }
}

The component takes in the text which can be copied by the user via the Text parameter. When the user click on the button the CopyTextToClipboard is invoked which calls the following JavaScript.

window.clipboardCopy = {
    copyText: function(text) {
        navigator.clipboard.writeText(text).then(function () {
            alert("Copied to clipboard!");
        })
        .catch(function (error) {
            alert(error);
        });
    }
};

The above function calls writeText to write the text provided from the CopyToClipboard component to the users clipboard.

We can use the component like this.

<CopyToClipboard Text="Copy this text" />

Which will produce the following output.

Solution 2: Replicating Bootstraps copy to clipboard

This time we’re going to replicate the functionality from Bootstrap docs. This is great for copying larger amounts of text. Here is the updated code for the CopyToClipboard component.

@inject IJSRuntime JSRuntime

<div class="position-relative" style="background-color: #f5f5f5">
    <pre>
    <code @ref="_codeElement">
            @ChildContent
        </code>
    </pre>
    <div style="position:absolute; top: 10px; right: 10px;">
        <button type="button" class="btn btn-primary" @onclick="CopyTextToClipboard">Copy</button>
    </div>
</div>

@code {

    private ElementReference _codeElement;

    [Parameter] public RenderFragment ChildContent { get; set; }

    private async Task CopyTextToClipboard()
    {
        await JSRuntime.InvokeVoidAsync("clipboardCopy.copyText", _codeElement);
    }
}

This time we’re taking in child content defined by the components consumer and rendering it inside a code tag. We’re capturing a reference to that element using Blazors @ref directive and passing that to JS when the copy button is clicked.

window.clipboardCopy = {
    copyText: function (codeElement) {
        navigator.clipboard.writeText(codeElement.textContent).then(function () {
            alert("Copied to clipboard!");
        })
        .catch(function (error) {
            alert(error);
        });
    }
}

The JavaScript code is largly the same as before. The only difference is we’re receiving an HTML element instead of a text string. When we call writeText we’re now passing in the text inside the code element using the textContent property.

We can use component like this.

<CopyToClipboard>
    @("<div class=\"clipboard-copy\">")
        @("<button type=\"button\" class=\"btn btn-primary\">Copy</button>")
    @("</div>")
</CopyToClipboard>

Which will produce the following output.

Summary

In this post I’ve show a couple of solutions for copying text to the users clipboard in Blazor. We started off by understanding the two API’s available in JavaScript for interacting with the clipboard, execCommand and the Clipboard API. We concluded that using the new Clipboard API was a better choice due to the execCommand API being marked obsolete.

We then looked at two solutions for implementing copy to clipboard functionality. The first allowed short string to be copied to the users clipboard via a simple component with a button which invoked a call into JavaScript. The second method showed how to copy larger volumes of text by passing an ElementReference to JavaScript and accessing its textContent property to retrieve the text before copying it to the clipboard.