# Clipboard Text

A selectable text field with a separate copy action and async feedback.

Page: https://sui.draco.dev/docs/components/clipboard-text

### Example: clipboard-text-demo

```tsx
import { ClipboardText } from "@workspace/ui/components/clipboard-text";
import type { ExampleProps } from "../types";
export default function Example({ locale }: ExampleProps) {
  const zh = locale === "zh-CN";
  return (
    <div className="w-full max-w-md">
      <ClipboardText
        text="bun add @workspace/ui"
        labels={{
          copy: zh ? "复制安装命令" : "Copy install command",
          copied: zh ? "已复制" : "Copied",
          failed: zh ? "复制失败，请手动复制" : "Copy failed. Copy manually.",
        }}
      />
    </div>
  );
}
```

## Installation

```bash
bunx --bun shadcn@latest add @sui/clipboard-text
```

Install with the shadcn CLI or use the shared `@workspace/ui` package. Follow the [installation guide](/docs/installation) to configure the registry, load styles, and choose import aliases.

```tsx
import { ClipboardText } from "@workspace/ui/components/clipboard-text";
```

## Usage

```tsx
<ClipboardText text="bun run dev" />
```

The displayed text remains selectable. A long value truncates visually; its full value is available on hover and the copy action always copies the complete value.

## Display and copy different values

Use `textToCopy` for a full address while showing a shorter label. `size` accepts `sm`, `default`, and `lg`.

### Example: clipboard-text-display-value

```tsx
import { ClipboardText } from "@workspace/ui/components/clipboard-text";
import type { ExampleProps } from "../types";
export default function Example({ locale }: ExampleProps) {
  const zh = locale === "zh-CN";
  return (
    <div className="grid w-full max-w-md gap-3">
      <ClipboardText
        text="/api/components"
        textToCopy="https://api.example.com/v1/components"
        size="sm"
        labels={{ copy: zh ? "复制完整 API 地址" : "Copy full API URL" }}
      />
      <ClipboardText
        text="https://api.example.com/v1/components?workspace=design-system&include=properties"
        size="lg"
        labels={{ copy: zh ? "复制地址" : "Copy URL" }}
      />
      <p className="text-muted-foreground text-sm">
        {zh
          ? "显示简短路径，复制完整地址；长文本可选择或悬停查看"
          : "Show a short path while copying the full URL. Long text can be selected or inspected on hover."}
      </p>
    </div>
  );
}
```

## Feedback and disabled state

`onCopy` receives the copied string only after the clipboard write succeeds. Handle `onCopyError` to provide a visible fallback. `labels` localizes the action and screen reader feedback. A pending write disables the copy button; a disabled field cannot start a write.

### Example: clipboard-text-feedback

```tsx
import { ClipboardText } from "@workspace/ui/components/clipboard-text";
import { Switch } from "@workspace/ui/components/switch";
import { useId, useState } from "react";
import type { ExampleProps } from "../types";
export default function Example({ locale }: ExampleProps) {
  const zh = locale === "zh-CN";
  const [enabled, setEnabled] = useState(true);
  const [notice, setNotice] = useState("");
  const id = useId();
  return (
    <div className="grid w-full max-w-md gap-4">
      <div className="flex items-center gap-2">
        <Switch id={id} checked={enabled} onCheckedChange={setEnabled} />
        <label htmlFor={id}>{zh ? "允许复制" : "Enable copying"}</label>
      </div>
      <ClipboardText
        text="workspace_72c31"
        disabled={!enabled}
        onCopy={() =>
          setNotice(zh ? "工作区 ID 已复制" : "Workspace ID copied.")
        }
        onCopyError={() =>
          setNotice(
            zh
              ? "浏览器无法访问剪贴板，请选择文本后手动复制"
              : "Clipboard access failed. Select the text and copy it manually.",
          )
        }
        labels={{
          copy: zh ? "复制工作区 ID" : "Copy workspace ID",
          copied: zh ? "已复制" : "Copied",
          failed: zh
            ? "无法复制，请手动复制"
            : "Copy unavailable. Copy manually.",
        }}
      />
      <p className="min-h-5 text-muted-foreground text-sm" role="status">
        {notice}
      </p>
    </div>
  );
}
```

The component uses the browser Clipboard API. If it is unavailable or permission is denied, it announces failure and calls `onCopyError`; users can select the text and copy it manually. It does not request clipboard access while rendering.

## API

| Prop | Type | Default |
| --- | --- | --- |
| `text` | `string` | Required |
| `textToCopy` | `string` | `text` |
| `size` | `"sm" \| "default" \| "lg"` | `"default"` |
| `disabled` | `boolean` | `false` |
| `resetDelay` | `number`, milliseconds | `1500` |
| `onCopy` | `(value: string) => void` | — |
| `onCopyError` | `(error: Error) => void` | — |
| `labels` | `{ copy?, pending?, copied?, failed? }` | English labels |
| `render` | React element or render function | `InputGroup` |

Standard root `div` props and refs are supported. Customize the root with `className` or Base UI's `render` composition. The copy control uses SUI [Input Group](/docs/components/input-group) and [Tooltip](/docs/components/tooltip); async state is exposed through `data-copy-status="idle|pending|copied|error"`. See the [Base UI composition API](https://base-ui.com/react/handbook/composition) for render and ref behavior.
