# CopyButton

**When to use:** Icon-only button that copies a value to the clipboard: an invoice number, an ID in a table row, an API key or share link inside an `Input`. For a labelled "Copy link" button, use `Button` with the `useClipboard` hook instead (see [Hooks.md](Hooks.md)).

**Keywords:** token, secret, reference number, snippet

**Import:** `import { CopyButton } from '@ahrowe/ui'`  
**Types:** `import type { CopyButtonProps, CopyButtonLabels } from '@ahrowe/ui'`

```tsx
import { CopyButton, Input, ThemeColor, showToast } from '@ahrowe/ui';

<span>
  {invoice.number} <CopyButton value={invoice.number} />
</span>

// inside a field
<Input label='API key' value={apiKey} readOnly suffix={<CopyButton value={apiKey} />} />

// a toast on success, where the button is not where the user is looking
<CopyButton value={url} onCopy={() => showToast('Link copied', { color: ThemeColor.Success })} />
```

It is an [ActionIcon](ActionIcon.md), so it takes the same `styleType` and `color`, and turns `Success` while copied. After a click the icon rotates into a check (through `AnimatedIcon`, held still under `prefers-reduced-motion`) for `timeout` ms, the accessible name and tooltip read "Copied", and a polite live region announces it, because a swapped icon or a changed `aria-label` alone is not read out. A refused write (an insecure context, a blocked iframe) announces "Could not copy" and calls `onError`; the icon stays as it was. `CopyButton` shows no toast of its own: pass one through `onCopy` / `onError` if you want it.

The live region is rendered as a sibling of the button, so `CopyButton` returns two elements. It is visually hidden and takes no space.

**Key props:**

| Prop | Type | Description |
|------|------|-------------|
| `value` | `string` | Text written to the clipboard on click (required) |
| `timeout` | `number` | How long the copied state shows, in ms (default `2000`) |
| `icon` | `IconDefinition \| ReactElement` | Icon before copying (default `faCopy`). The swap animates only when both icons are FontAwesome definitions |
| `copiedIcon` | `IconDefinition \| ReactElement` | Icon while copied (default `faCheck`) |
| `onCopy` | `(value: string) => void` | Called after a successful copy |
| `onError` | `() => void` | Called when the clipboard refuses the write. `useClipboard` returns the reason |
| `onClick` | `(event: MouseEvent<HTMLButtonElement>) => void` | Called on every click, before the copy |
| `color` | `ColorValue` | Its colour at rest (default `Neutral`); `Success` while copied |
| `ref` | `Ref<HTMLButtonElement>` | Ref to the button |

**Global defaults:** adopts `ConfigProvider`, e.g. `defaultProps={{ CopyButton: { timeout: 1500 } }}`. See [ConfigProvider.md](ConfigProvider.md).

**Slots:** `root` `icon`

**Labels:** `copy` `copied` `failed`: the text this component renders of its own. Pass `labels` to override any of them, on the component or app-wide through `ConfigProvider`; they merge per key. Type: `CopyButtonLabels`.
