Copy to Clipboard in Blazor
Tags: blazor, csharp, dotnet, webdev
Published: 2020-04-29 18:52:33

---
title: Copy to Clipboard in Blazor
published: true
date: 2020-04-29 08:38:48 UTC
tags: Blazor,CSharp,DotNet,WebDev
canonical_url: https://chrissainty.com/copy-to-clipboard-in-blazor/
---

 ![Copy to Clipboard in Blazor](https://chrissainty.com/content/images/2020/04/copy-to-clipboard-in-blazor.jpg)

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.

![Copy to Clipboard in Blazor](https://chrissainty.com/content/images/2020/04/github-copytoclipboard.jpg)

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](https://getbootstrap.com). Each code example has a copy button in the top right corner allowing developers to copy the sample code straight to their clipboard.

![Copy to Clipboard in Blazor](https://chrissainty.com/content/images/2020/04/bootstrap-copytoclipboard.jpg)

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`](https://developer.mozilla.org/en-US/docs/Web/API/Document/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](https://caniuse.com/#search=execcommand) shows lots of green (95.63%).

![Copy to Clipboard in Blazor](https://chrissainty.com/content/images/2020/04/caniuse-execcommand.jpg)

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

![Copy to Clipboard in Blazor](https://chrissainty.com/content/images/2020/04/execcommand-obsolite.jpg)

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

### Clipboard API

The new [Clipboard API](https://developer.mozilla.org/en-US/docs/Web/API/Clipboard_API) has the ability to read and write to the clipboard both syncronously and asyncronously, as well as integrating with the [Permissions API](https://developer.mozilla.org/en-US/docs/Web/API/Permissions_API) to ensure the user has given permission to do so.

The API breaks down into 2 interfaces, `Clipboard` and `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()`](https://developer.mozilla.org/en-US/docs/Web/API/Clipboard/read)**Requests arbitrary data (such as images) from the clipboard, returning a [`Promise`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise). When the data has been retrieved, the promise is resolved with a [`DataTransfer`](https://developer.mozilla.org/en-US/docs/Web/API/DataTransfer) object that provides the data.
- **[`readText()`](https://developer.mozilla.org/en-US/docs/Web/API/Clipboard/readText)**Requests text from the system clipboard; returns a `Promise` which is resolved with a [`DOMString`](https://developer.mozilla.org/en-US/docs/Web/API/DOMString) containing the clipboard's text once it's available.
- **[`write()`](https://developer.mozilla.org/en-US/docs/Web/API/Clipboard/write)**Writes arbitrary data to the system clipboard. This asynchronous operation signals that it's finished by resolving the returned `Promise`.
- **[`writeText()`](https://developer.mozilla.org/en-US/docs/Web/API/Clipboard/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.

![Copy to Clipboard in Blazor](https://chrissainty.com/content/images/2020/04/caniuse-clipboard-writetext.jpg)

However, the browsers that don't support this also don't support Blazor so that makes thing 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.

<!--kg-card-begin: markdown-->
```
@inject IJSRuntime

<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);
    }
}

```
<!--kg-card-end: markdown-->

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.

<!--kg-card-begin: markdown-->
```
window.clipboardCopy = {
    copyText: function(text) {
        navigator.clipboard.writeText(text).then(function () {
            alert("Copied to clipboard!");
        })
        .catch(function (error) {
            alert(error);
        });
    }
};

```
<!--kg-card-end: markdown-->

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.

<!--kg-card-begin: markdown-->
```
<CopyToClipboard Text="Copy this text" />

```
<!--kg-card-end: markdown-->

Which will produce the following output.

![Copy to Clipboard in Blazor](https://chrissainty.com/content/images/2020/04/blazor-github-copytoclipboard-1.jpg)

## 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.

<!--kg-card-begin: markdown-->
```
<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);
    }
}

```
<!--kg-card-end: markdown-->

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.

<!--kg-card-begin: markdown-->
```
window.clipboardCopy = {
    copyText: function (codeElement) {
        navigator.clipboard.writeText(codeElement.textContent).then(function () {
            alert("Copied to clipboard!");
        })
        .catch(function (error) {
            alert(error);
        });
    }
}

```
<!--kg-card-end: markdown-->

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.

<!--kg-card-begin: markdown-->
```
<CopyToClipboard>
    @("<div class=\"clipboard-copy\">")
        @("<button type=\"button\" class=\"btn btn-primary\">Copy</button>")
    @("</div>")
</CopyToClipboard>

```
<!--kg-card-end: markdown-->

Which will produce the following output.

![Copy to Clipboard in Blazor](https://chrissainty.com/content/images/2020/04/blazor-bootstrap-copytoclipboard.jpg)

## 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.