<!-- Generated by scripts/gen-docs.mts from the JSDoc in registry/. Do not edit; run `pnpm run docs`. -->

# CopyButton

A button that puts a piece of text on the clipboard: an API key, a link, a command. On a click it copies `value`, then for two seconds shows a check and says "Copied" (or a cross and "Couldn't copy" when the browser refuses), and screen readers hear the same, politely, once. It uses the Clipboard API, and a text selection where that is not available.

```tsx
import { CopyButton } from "@/components/ouro/copy-button/copy-button";
```

## Example

```tsx
<CopyButton value={apiKey} label="Copy key" />
<CopyButton value={url} label="Copy link" hideLabel variant="plain" />
```

## Use instead when

- Use `CodeBlock` instead for code or a command shown with its own copy button.

## Props

Type: `CopyButtonProps`.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `className` | `string` |  | Layout only: margins, grid placement (`ms-auto`). Appearance classes warn in development. |
| `copiedLabel` | `string` | `"Copied"` | What the button says, and screen readers hear, once the text is on the clipboard. |
| `failedLabel` | `string` | `"Couldn't copy"` | What the button says, and screen readers hear, when the browser refused to copy. |
| `hideLabel` | `boolean` |  | Shows only the icon; the label stays the button's name for screen readers. For a corner of a code block or a field. |
| `label` | `string` | `"Copy"` | The button's label, and its name for screen readers when `hideLabel` is set. |
| `onCopy` | `((value: string) => void)` |  | Called with the text once it is on the clipboard. |
| `ref` | `Ref<HTMLButtonElement>` |  | Reaches the rendered element. |
| `size` | `"sm" \| "md" \| "lg"` | `"sm"` | Control size, as Button's. |
| `value` (required) | `string` |  | The text the button puts on the clipboard. |
| `variant` | `"solid" \| "soft" \| "outline" \| "plain"` | `"outline"` | Visual weight, as Button's. |

## Native attributes

Also accepts the attributes in React's `ButtonHTMLAttributes` and `HTMLAttributes` (`id`, `aria-*`, event handlers), passed to the rendered element, except those named on this page.

## Don't use

These are not props. Passing one fails the type check with the fix in the error, and in development a console message names the fix.

- `children`: Not a prop. The label is `label`: `<CopyButton value={url} label="Copy link" />`.
- `content`: Not a prop. The text to copy is `value`: `<CopyButton value={token} />`.
- `onClick`: Not a prop. CopyButton copies on click itself; to react to a copy, pass `onCopy`.
- `text`: Not a prop. The text to copy is `value`: `<CopyButton value={token} />`.
- `timeout`: Not a prop. The confirmation is `copiedLabel`, and it lasts two seconds.

## `className` is for layout only

Pass margins, width and grid placement (`mt-4`, `w-full`, `col-span-2`). Your classes always win over Ouro UI's: CopyButton merges `className` last with `cn` (tailwind-merge), so a class that conflicts with its own replaces it.[^layout-classes]

Appearance comes from props, not classes. In development, a class that sets appearance logs one warning per component instance, naming the prop to use instead. A class sets appearance when, after its variants (`hover:`, `sm:`) and any `!` are removed, it starts with `bg-`, `text-`, `border-`, `rounded-`, `shadow-`, `font-`, `ring-`, `from-`, `via-`, `to-`, `fill-` or `stroke-`, or is `border`, `rounded`, `shadow` or `ring`, or has a `dark:` variant. Text wrapping, overflow and table layout classes (`text-wrap`, `text-ellipsis`, `border-collapse`) are layout and do not warn.

Alignment classes (`text-center`) warn too: set alignment on a parent element.

[^layout-classes]: test:registry/ouro/components/ouro/copy-button/copy-button.test.tsx::CopyButton > forwards a ref, takes button attributes, and lets app layout classes win verify:testExists(registry/ouro/components/ouro/copy-button/copy-button.test.tsx::CopyButton > forwards a ref, takes button attributes, and lets app layout classes win)
