# Clipboard

A button that copies a value and shows that it was copied.

```tsx title="hero.tsx"
"use client";
import * as React from "react";
import { Clipboard } from "@logic-ui/react/clipboard";

export default function ExampleClipboard() {
  return (
    <Clipboard.Root
      value="pnpm add @logic-ui/react"
      className="flex items-center gap-2 rounded-md border border-neutral-200 bg-white py-1 pr-1 pl-3 text-neutral-950 data-copied:border-green-600 dark:border-neutral-800 dark:bg-neutral-950 dark:text-white"
    >
      <code className="font-mono text-sm">pnpm add @logic-ui/react</code>
      <Clipboard.Trigger
        aria-label="Copy the install command"
        className="group relative flex size-8 cursor-pointer items-center justify-center rounded border-none bg-transparent p-0 text-inherit hover:bg-neutral-100 focus-visible:outline-2 focus-visible:-outline-offset-1 focus-visible:outline-neutral-950 dark:hover:bg-neutral-800 dark:focus-visible:outline-white"
      >
        {/* The copy icon gives way to the check while copied. */}
        <CopyIcon className="group-data-copied:invisible" />
        <Clipboard.Indicator className="absolute inset-0 flex items-center justify-center text-green-600">
          <CheckIcon />
        </Clipboard.Indicator>
      </Clipboard.Trigger>
    </Clipboard.Root>
  );
}

function CopyIcon(props: React.ComponentProps<"svg">) {
  return (
    <svg
      width="16"
      height="16"
      viewBox="0 0 16 16"
      fill="none"
      aria-hidden
      {...props}
    >
      <rect
        x="5"
        y="5"
        width="8.5"
        height="8.5"
        rx="1.5"
        stroke="currentColor"
      />
      <path
        d="M3 10.5V3.5A1 1 0 0 1 4 2.5h6.5"
        stroke="currentColor"
        strokeLinecap="round"
      />
    </svg>
  );
}

function CheckIcon(props: React.ComponentProps<"svg">) {
  return (
    <svg
      width="16"
      height="16"
      viewBox="0 0 16 16"
      fill="none"
      aria-hidden
      {...props}
    >
      <path
        d="M3.5 8.5 6.5 11.5 12.5 4.5"
        stroke="currentColor"
        strokeWidth="1.5"
        strokeLinecap="round"
        strokeLinejoin="round"
      />
    </svg>
  );
}
```

## Anatomy

Import the component and assemble its parts:

```jsx title="Anatomy"
import { Clipboard } from "@logic-ui/react/clipboard";

<Clipboard.Root>
  <Clipboard.Trigger>
    <Clipboard.Indicator />
  </Clipboard.Trigger>
</Clipboard.Root>;
```

## Examples

### Copied state

Every part has a `data-copied` attribute while the value was copied less than `timeout` milliseconds ago (2 seconds by default).
Style the parts with it, and listen to `onCopiedChange` to react in code.

```tsx title="Longer copied state"
<Clipboard.Root
  value={url}
  timeout={4000}
  onCopiedChange={(copied) => console.log(copied)}
>
  <Clipboard.Trigger>Copy link</Clipboard.Trigger>
</Clipboard.Root>
```

### Errors

Browsers can refuse to write to the clipboard, for example on an insecure origin or without a user gesture.
The copied state then stays off and `onCopyError` receives the error.

```tsx title="Report a refused copy"
<Clipboard.Root value={token} onCopyError={() => toast.error("Copy failed")}>
  <Clipboard.Trigger>Copy token</Clipboard.Trigger>
</Clipboard.Root>
```

### Indicator

`Clipboard.Indicator` renders only while copied. Set `keepMounted` to keep it in the DOM and animate it with `data-copied`.

```tsx title="Fade the check in"
<Clipboard.Root value={url}>
  <Clipboard.Trigger className="group relative size-8">
    <CopyIcon className="group-data-copied:invisible" />
    <Clipboard.Indicator
      keepMounted
      className="absolute inset-0 flex items-center justify-center text-green-600 opacity-0 transition-opacity duration-200 data-copied:opacity-100"
    >
      <CheckIcon />
    </Clipboard.Indicator>
  </Clipboard.Trigger>
</Clipboard.Root>
```

### Styling

Every part has `data-copied` while copied, so Tailwind's `data-copied:` variant styles it, and `group-data-copied:` styles what's inside a part.

## API reference

### Clipboard.Root

Groups the clipboard parts and holds the copied state.
Renders a `<div>` element.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| value (required) | `string` | - | The text written to the clipboard. |
| timeout | `number` | `2000` | Time in milliseconds before `copied` goes back to `false`. |
| onCopiedChange | `(copied: boolean) => void` | - | Called when `copied` changes. |
| onCopyError | `(error: unknown) => void` | - | Called when the browser refuses to write to the clipboard. |
| className | `string` | - | CSS class applied to the element. |
| style | `React.CSSProperties` | - | Style applied to the element. |
| render | `React.ReactElement \| ((props, state) => React.ReactElement)` | - | Replaces the element with another tag or component, or composes it with one. Takes an element, or a function that receives the props and the state. |

| Data attribute | Description |
| --- | --- |
| `data-copied` | Present while the value was copied less than `timeout` ms ago. |

### Clipboard.Trigger

A button that copies the value of `Clipboard.Root`.
Renders a `<button>` element.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| className | `string` | - | CSS class applied to the element. |
| style | `React.CSSProperties` | - | Style applied to the element. |
| render | `React.ReactElement \| ((props, state) => React.ReactElement)` | - | Replaces the element with another tag or component, or composes it with one. Takes an element, or a function that receives the props and the state. |

| Data attribute | Description |
| --- | --- |
| `data-copied` | Present while the value was copied less than `timeout` ms ago. |

### Clipboard.Indicator

Shows that the value was just copied, for example a check icon.
Renders a `<span>` element, only while `copied` is `true` unless `keepMounted` is set.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| keepMounted | `boolean` | `false` | Keep the element in the DOM when the value is not copied. Style it with `data-copied`. |
| className | `string` | - | CSS class applied to the element. |
| style | `React.CSSProperties` | - | Style applied to the element. |
| render | `React.ReactElement \| ((props, state) => React.ReactElement)` | - | Replaces the element with another tag or component, or composes it with one. Takes an element, or a function that receives the props and the state. |

| Data attribute | Description |
| --- | --- |
| `data-copied` | Present while the value was copied less than `timeout` ms ago. |
