# Clipboard

> Put a string on the visitor's system clipboard. One verb, callable from any action, so a copy button — an API key, a share link, a code snippet, an invoice number — is ordinary app code. The platform ships the mechanism and renders none of the chrome.

<!-- id: ui-clipboard · area: ui · stability: stable · html: https://osysharp.com/reference/ui/clipboard/ -->

## Summary        {#summary}
`Clipboard.Copy(text)` writes a string to the visitor's system clipboard. It is available in every component, and it
is the whole surface: one verb, one argument.

It exists because "copy this" is a browser act with no server equivalent — the clipboard belongs to the person at the
keyboard, not to your app or to the machine your app runs on. So it is a verb, alongside [Navigation](https://osysharp.com/reference/ui/navigation/)'s and
[theme tokens](https://osysharp.com/reference/ui/theming/)'s, rather than a function you could call from a server body.

The platform ships **no copy button**. Where it lives, what it looks like, and whether it says "Copied!" afterwards
are your layout's decisions.

## Signature      {#signature}
```osy syntax
Clipboard.Copy(text)     // put `text` on the system clipboard; returns nothing
```

## Description    {#description}

### Copying text — where the call goes   {#calling}
It is an ordinary statement in an action body:

```osy title="a copy button" test app=drop-ship-order
component ShareLink(string Url) {
  action Copy() { Clipboard.Copy(Url); }

  render {
    Row {
      Text(Url);
      Button("Copy", onPress: Copy);
    }
  }
}
```

### Showing a "Copied!" — the feedback is yours   {#feedback}
The verb returns nothing, so the "Copied!" is yours to render — which is what you want, because the wording, the
placement and how long it lingers are design decisions. Set your own state on the click:

```osy title="Copied!, for a moment" test app=drop-ship-order
component CopyKey(string Key) {
  bool copied = false;

  action Copy() {
    Clipboard.Copy(Key);
    copied = true;
  }

  render {
    Button(copied ? "Copied!" : "Copy key", onPress: Copy);
  }
}
```

### The text goes across verbatim    {#verbatim}
Whatever you pass is what lands on the clipboard, byte for byte. Nothing is escaped, trimmed, or rewritten — a code
snippet containing `<script>` arrives as those nine characters, because a clipboard is not a rendering surface and
"helpfully" sanitizing it would corrupt the very thing someone asked to copy.

That also means **you** decide what is copyable. Copying a value your visitor cannot see is not a boundary the
clipboard enforces; the ordinary rules about what a component may read still apply, and they apply here unchanged.

### When it cannot copy    {#failures}
A browser may refuse a clipboard write — most often because the page is served over plain `http` from an address that
is not `localhost`, where the modern clipboard API does not exist at all. The platform falls back to the older
selection-based copy, which works there, so a copy button on an internal http-only deployment still functions.

If both paths fail, **nothing is copied and the browser console says so**, naming the reason. The action itself
carries on: a refused copy never throws and never aborts the rest of your body.

### Can I READ the clipboard? No   {#no-read}
There is no `Clipboard.Read`. Reading someone's clipboard is a permission-gated act with a prompt attached, and
nothing in the platform needs it — a paste arrives through an ordinary `Input` the moment the visitor presses the
keys. If you have a case that genuinely needs it, that is a conversation to have rather than a gap to work around.

### Can I name something `Clipboard`? — shadowing   {#shadowing}
`Clipboard` is an ambient name, so an identifier of your own wins — a parameter, a state member or a variable called
`Clipboard` shadows it, exactly as it does for [Navigation](https://osysharp.com/reference/ui/navigation/) and [theme tokens](https://osysharp.com/reference/ui/theming/). Nothing you already named breaks
because this verb exists.

### Copying from rendered markdown    {#markdown}
A `Markdown(...)` document renders inside the atom, so your app cannot reach the code blocks inside it to hang a
button on them. That case has its own opt-in — see [Markdown — rendering markdown text](https://osysharp.com/reference/ui/markdown/) `#code-actions`, which renders a copy control per
code block using an icon and tooltip you supply.

## See also {#see-also}
- [Markdown — rendering markdown text](https://osysharp.com/reference/ui/markdown/) — per-code-block copy inside a rendered document
- [Navigation](https://osysharp.com/reference/ui/navigation/) — the other browser verbs (`Go`, `Open`, `Close`)
- [theme tokens](https://osysharp.com/reference/ui/theming/) — `Theme.Toggle()` / `Theme.Set(mode)`, the same shape
- [component](https://osysharp.com/reference/ui/component/) — where actions live
