TextCopy: clipboard access for .NET without the platform branches
A cross platform package to copy text to and from the clipboard.
At a glance
- What is it?
- TextCopy is a MIT licensed NuGet package that wraps the clipboard behind a static service, an injectable instance and an interface, and it works on Windows, macOS, Linux, Xamarin and Blazor WebAssembly. The static API is explicitly not supported on Blazor, which needs the instance API and the browser clipboard APIs instead.
- Who is it for?
- Adopt TextCopy if you write .NET code that needs the clipboard and want one call site that works on Windows, macOS and Linux, including Blazor, rather than platform conditionals in every project. Skip it if you only need one platform, since the built-in APIs are already there, and skip it if you are on Blazor and want a static call, because that is explicitly not supported.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 10 days ago.
- What is it written in?
- Mainly C#, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
One clipboard call that travels across platforms
TextCopy is a cross platform package to copy text to and from the clipboard, published on NuGet and licensed MIT. The problem it addresses is the one every .NET developer hits on their second project, where the clipboard API is a Windows nicety on .NET Framework, a different one on .NET Core, a shell out to xsel on Linux, and a JavaScript interop call in the browser. TextCopy exists so that the call site does not change. The API is deliberately small. Setting text synchronously is a single call, and there is an asynchronous variant.
ClipboardService.SetText("Text to place in clipboard");await ClipboardService.SetTextAsync("Text to place in clipboard");Reading works the same way, with a synchronous and an asynchronous form.
var text = ClipboardService.GetText();var text = await ClipboardService.GetTextAsync();And clearing the clipboard is writing an empty string, which is a nice detail because it means there is no separate clear operation whose behaviour could differ from a set on some platform.
ClipboardService.SetText("");await ClipboardService.SetTextAsync("");The two async methods are the ones you would reach for in any UI code, since a clipboard write on a modern desktop is a message loop operation rather than a memory copy, and the package is MIT licensed so it drops into a commercial product without ceremony.
The instance API and dependency injection, with a mock for tests
The static API is only half the design, and the other half is the one that matters for testable code. In addition to the static API, there is an instance API, where you construct a Clipboard yourself and call the same methods on it.
Clipboard clipboard = new();
clipboard.SetText("Text to place in clipboard");That instance can be injected into an IServiceCollection, which is the part that pays off in a test suite.
serviceCollection.InjectClipboard();The instance should be injected by using IClipboard, and there is also an InjectMockClipboard that injects an instance of MockClipboard with all methods stubbed out. That is the argument for the instance API. A static call to the system clipboard is untestable without touching the real clipboard, which is global state shared with the rest of the machine and with the developer running the tests, and a test that copies to the real clipboard overwrites whatever the developer had copied. The mock exists so that a component under test can be given a clipboard whose contents you control. The repository carries a Blazor sample project alongside the library, which is where the injection examples come from.
Blazor is the exception, and the README says so plainly
The one platform where the static API does not work is Blazor, and the reason is technical rather than an oversight. Due to the dependency on JSInterop, the static ClipboardService is not supported on Blazor, so the recommendation is to inject an IClipboard instead. The startup code shows the difference, with the builder and the service collection in scope.
var builder = WebAssemblyHostBuilder.CreateDefault();
var serviceCollection = builder.Services;
serviceCollection.InjectClipboard();
builder.RootComponents.Add<App>("app");And the consuming component injects the interface with the standard attribute.
public partial class IndexModel :
ComponentBase
{
[Inject]
public IClipboard Clipboard { get; set; }
public string Content { get; set; }
public Task CopyTextToClipboard() =>
Clipboard.SetTextAsync(Content);
public async Task ReadTextFromClipboard() =>
Content = await Clipboard.GetTextAsync();
}The reason the static API fails here is worth understanding. A static method has no instance and therefore no access to the JavaScript runtime that a Blazor WebAssembly application needs in order to call into the browser, so a static call has nowhere to dispatch the interop. The instance API works because the object is constructed in a context that knows about the runtime. The browser side has its own requirement, since Blazor support requires the clipboard.readText and clipboard.writeText browser APIs, which is a check on the browser rather than on the .NET runtime.
The support matrix is broad, and Linux has a system dependency
The supported list is a specific set of runtime combinations rather than a vague claim of cross platform, and it covers more ground than most libraries of this size. On Windows it supports .NET Framework 4.6.1 and up, .NET Core 2.0 and up, and Mono 5.0 and up. On macOS it supports .NET Core 2.0 and up and Mono 5.20.1 and up. On Linux, the same pair, .NET Core 2.0 and up and Mono 5.20.1 and up. Then there is Xamarin.Android 9.0 and up, Xamarin.iOS 10.0 and up, and Blazor WebAssembly 6.0 and up. The practical note is the one at the end of the file, that Linux uses xsel to access the clipboard and as such it needs to be installed and callable. That is the kind of detail that turns a green build into a red one at runtime on a container, because a Linux container image without a display and without xsel will fail at the point of the first clipboard call rather than at startup. It is a one-line fix on a developer machine and a missing layer in a container image, so it is worth knowing before you deploy. The Mono entries are of historical interest now, since Mono is in maintenance, but their presence tells you how long the package has been keeping up with the platform surface it targets.
The release history is where the caution is
The recent releases are 6.2.1 from 2022-12-16, 6.2.0 from 2022-11-08 and 5.0.0 from 2022-01-07, which puts the last tagged release a while back, and the version numbers have been on the 6.x line since 2022. The repository itself is not archived, and the last push was on 2026-10-14, so the code is still being touched, but there are no new tags and the release notes live in the closed milestones on GitHub rather than in a changelog file, which means the history of what changed is not in the repository. That combination, code being changed without releases, is the situation where you cannot answer the question you want to ask, which is whether the version you are pinning contains the fix you need. There is a global.json at the top of the tree pinning an SDK version, which is a good sign about build reproducibility, and the top level is otherwise small, with a .gitattributes, a .github directory for the build workflow, a license.txt and a src/ directory holding the library and its tests. The snippet anchors in the README point at file and line references inside src/Tests/Snippets.cs, so the examples are generated from a tested source file rather than written by hand, which is a small but meaningful difference when you are trusting a snippet.
Where TextCopy is the wrong choice
The first limit is that the package is thin. It wraps the clipboard, and that is all it does, so if your requirement is copying files, images or arbitrary data formats rather than text, you need something else entirely, and the name is accurate in that respect. The second is that the value of a cross platform wrapper is proportional to how many platforms you actually target, and a Windows-only .NET application should just use the framework API, with fewer dependencies and no surprises. The third is the maintenance point above, and it matters more for a clipboard package than it would for something else, because a clipboard package is the kind of small utility that sits in a dependency graph for years without anyone revisiting it, and the platforms it wraps do change. The fourth is that the static API, which is what the README leads with, is the one that cannot be tested and does not work on Blazor, so a codebase that adopts it for convenience is the codebase that later has to be refactored to the interface when the platform or the test story demands it. The instance API with IClipboard is the shape that ages well, and it is a small enough difference that picking it from the start costs almost nothing.
Editorial conclusion
Adopt TextCopy if you write .NET code that needs the clipboard and want one call site that works on Windows, macOS and Linux, including Blazor, rather than platform conditionals in every project. Skip it if you only need one platform, since the built-in APIs are already there, and skip it if you are on Blazor and want a static call, because that is explicitly not supported. Verify first that the target runtime is in the supported list, that xsel is installed and callable on Linux, and that your browser exposes the clipboard read and write APIs if you are on Blazor WebAssembly.
Frequently asked questions
How do I copy text to the clipboard with TextCopy?
Call the static ClipboardService.SetText with the text, or await ClipboardService.SetTextAsync. Reading is the mirror image with ClipboardService.GetText and ClipboardService.GetTextAsync, and clearing the clipboard is writing an empty string with either SetText or SetTextAsync.
Why does TextCopy not work with the static API in Blazor?
Because of the dependency on JSInterop, the static ClipboardService is not supported on Blazor. The README says to inject an IClipboard instead, using serviceCollection.InjectClipboard() at startup and the Inject attribute in the consuming component, and notes that Blazor support requires the browser clipboard.readText and clipboard.writeText APIs.
What does TextCopy need on Linux?
Linux uses xsel to access the clipboard, so xsel needs to be installed and callable. The supported list also covers .NET Framework 4.6.1 and up, .NET Core 2.0 and up and Mono 5.0 and up on Windows, .NET Core 2.0 and up and Mono 5.20.1 and up on macOS and Linux, Xamarin.Android 9.0 and up, Xamarin.iOS 10.0 and up, and Blazor WebAssembly 6.0 and up.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/copytext-textcopy)Was this useful?