Copying text to the clipboard in a Blazor application
Many websites provide a button to copy a value to the clipboard. For instance, after generating a token on Azure, you can copy the token to the clipboard:
A browser provides an API to write to the clipboard or read from it. Modern browsers implements navigator.clipboard
to access the clipboard.
source: https://caniuse.com/#feat=mdn-api_clipboard_readtext
You can call these methods using IJSRuntime
. Instead of using the runtime directly in your components, you can create a service to manage the clipboard.
using System.Threading.Tasks;
using Microsoft.JSInterop;
public sealed class ClipboardService
{
private readonly IJSRuntime _jsRuntime;
public ClipboardService(IJSRuntime jsRuntime)
{
_jsRuntime = jsRuntime;
}
public ValueTask<string> ReadTextAsync()
{
return _jsRuntime.InvokeAsync<string>("navigator.clipboard.readText");
}
public ValueTask WriteTextAsync(string text)
{
return _jsRuntime.InvokeVoidAsync("navigator.clipboard.writeText", text);
}
}
Then, you can register the service in the Program.cs
file or Startup.cs
:
builder.Services.AddScoped<ClipboardService>();
Finally, you can use the service in your component:
@page "/"
@inject ClipboardService ClipboardService
<h1>Demo Clipboard!</h1>
<button @onclick="ReadFromClipboard">Read from clipboard</button>
<button @onclick="CopyToClipboard">Copy to clipboard</button>
@text
@code {
string text;
async Task ReadFromClipboard()
{
// Reading from the clipboard may be denied, so you must handle the exception
try
{
text = await ClipboardService.ReadTextAsync();
}
catch
{
Console.WriteLine("Cannot read from clipboard");
}
}
async Task CopyToClipboard()
{
// Writing to the clipboard may be denied, so you must handle the exception
try
{
await ClipboardService.WriteTextAsync("https://www.meziantou.net");
}
catch
{
Console.WriteLine("Cannot write text to clipboard");
}
}
}
Note that the first time, the user may need to allow access to the clipboard:
#Creating a nice Copy button
It's common to temporarily change the button text to "copied to clipboard" after clicking the button. This is pretty easy to do using Blazor:
@using System.Threading
@implements IDisposable
@inject ClipboardService ClipboardService
<button class="btn btn-primary" @onclick="CopyToClipboard" disabled=@state.IsDisabled>
<i class="@state.IconClassName"></i> @state.Text
</button>
@code {
CancellationTokenSource cts = new();
State state = new("Copy", "oi oi-clipboard");
async Task CopyToClipboard()
{
var temp = state;
state = new("Copied", "oi oi-check", IsDisabled: true);
await ClipboardService.WriteTextAsync("https://www.meziantou.net");
await Task.Delay(TimeSpan.FromSeconds(2), cts.Token);
state = temp;
}
public void Dispose()
{
cts.Cancel(); // Cancel Task.Delay
cts.Dispose();
}
record State(string Text, string ClassName, bool IsDisabled = false);
}
Do you have a question or a suggestion about this post? Contact me!