> For AI agents: the complete documentation index is available at https://wallarm.github.io/design-system/llms.txt, the full documentation bundle is available at https://wallarm.github.io/design-system/llms-full.txt.

# Copyable

Click-to-copy is a **behaviour pattern**, not a component.
Any existing element — a Button, InlineCodeSnippet, Attribute value, table cell, or DropdownMenuItem — copies a value on click and confirms it.

### Feedback rules

1. **Element can change itself** (button, icon button, code snippet action): swap in place. Copy icon → Check, label "Copy code" → "Copied" at the idle width, tooltip "Click to copy" → "Copied".
2. **Clickable text without an icon** (inline code snippet, a value): tooltip only.
3. **Element disappears after the action or has nothing to transform** (menu item): toast "Copied".

Never two feedbacks at once. Copied state resets after \~2 s.

[Source](https://github.com/wallarm/design-system/tree/main/packages/design-system/src/components/Copyable) · [Storybook](https://wallarm.github.io/design-system/storybook/?path=/docs/patterns-click-to-copy--overview)

```tsx
import { Button } from '@wallarm-org/design-system/Button';
import { Copyable, CopyableIcon } from '@wallarm-org/design-system/Copyable';
import { Copy } from '@wallarm-org/design-system/icons';

export const IconButton = () => (
  <Copyable text={SAMPLE_TEXT} tooltip>
    <Button variant='ghost' color='neutral' size='small' aria-label='Copy'>
      <CopyableIcon />
    </Button>
  </Copyable>
);
```

## Usage

```tsx
import { Button } from '@wallarm-org/design-system/Button';
import { Copyable, CopyableIcon } from '@wallarm-org/design-system/Copyable';
import { Copy } from '@wallarm-org/design-system/icons';
```

## Examples

### Labelled button

A labelled button using `CopyableLabel` for width-stable text swap.
The wrapper always occupies the width of the wider label, preventing
layout shift when the text toggles between "Copy code" and "Copied".

```tsx
import { Button } from '@wallarm-org/design-system/Button';
import { Copyable, CopyableIcon, CopyableLabel } from '@wallarm-org/design-system/Copyable';
import { Copy } from '@wallarm-org/design-system/icons';
import { VStack } from '@wallarm-org/design-system/Stack';

export const LabelledButton = () => (
  <VStack align='start' gap={16}>
    <Copyable text={SAMPLE_TEXT} tooltip>
      <Button variant='secondary' size='medium'>
        <CopyableIcon /> <CopyableLabel idle='Copy code' copied='Copied' />
      </Button>
    </Copyable>
    <Copyable text={SAMPLE_TEXT} tooltip>
      <Button variant='ghost' color='neutral' size='medium'>
        <CopyableIcon /> <CopyableLabel idle='Copy link' copied='Copied' />
      </Button>
    </Copyable>
  </VStack>
);
```

### In inline code snippet

`InlineCodeSnippet` has built-in click-to-copy with tooltip-only feedback
(feedback rule 2 — clickable text without an icon).

```tsx
import { InlineCodeSnippet } from '@wallarm-org/design-system/CodeSnippet';
import { Text } from '@wallarm-org/design-system/Text';

export const InInlineCodeSnippet = () => (
  <Text size='sm' color='secondary'>
    To start creating an interface, run <InlineCodeSnippet code='npm install @wads/ui' size='md' />
  </Text>
);
```

### In code snippet

Inside a `CodeSnippet`, the `CodeSnippetCopyButton` uses the Copyable
pattern internally — icon-only, ghost/neutral, with tooltip feedback.

```tsx
import { CodeSnippetActions, CodeSnippetAdapterProvider, CodeSnippetCode, CodeSnippetContent, CodeSnippetCopyButton, CodeSnippetRoot, plainAdapter } from '@wallarm-org/design-system/CodeSnippet';

export const InCodeSnippet = () => (
  <CodeSnippetAdapterProvider adapter={plainAdapter}>
    <CodeSnippetRoot code={SAMPLE_CODE} language='text'>
      <CodeSnippetActions>
        <CodeSnippetCopyButton />
      </CodeSnippetActions>
      <CodeSnippetContent>
        <CodeSnippetCode />
      </CodeSnippetContent>
    </CodeSnippetRoot>
  </CodeSnippetAdapterProvider>
);
```

### Value text

A plain text value wrapped in `Copyable` with tooltip feedback (feedback
rule 2). This is the pattern for Attribute values or any non-interactive
text that should be copyable on click.

```tsx
import { Attribute, AttributeLabel, AttributeValue } from '@wallarm-org/design-system/Attribute';
import { Copyable } from '@wallarm-org/design-system/Copyable';
import { Text } from '@wallarm-org/design-system/Text';

export const ValueText = () => {
  const value = '192.168.1.1';

  return (
    <Attribute>
      <AttributeLabel>IP Address</AttributeLabel>
      <AttributeValue>
        <Copyable text={value} tooltip>
          <Text size='sm'>{value}</Text>
        </Copyable>
      </AttributeValue>
    </Attribute>
  );
};
```

### Dropdown menu item with toast

When the element disappears after the action (like a dropdown menu item),
use toast feedback via `onCopied` (feedback rule 3). The `Copyable`
component does not bake in toast — the consumer fires it from the callback.

```tsx
import { Button } from '@wallarm-org/design-system/Button';
import { Copyable } from '@wallarm-org/design-system/Copyable';
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuItemIcon, DropdownMenuItemText, DropdownMenuTrigger } from '@wallarm-org/design-system/DropdownMenu';
import { Copy } from '@wallarm-org/design-system/icons';
import { toaster } from '@wallarm-org/design-system/Toast';

export const DropdownMenuItemWithToast = () => {
  const handleCopied = () => {
    toaster.create({ title: 'Copied', type: 'default', variant: 'simple' });
  };

  return (
    <DropdownMenu>
      <DropdownMenuTrigger asChild>
        <Button variant='outline' color='neutral'>
          Actions
        </Button>
      </DropdownMenuTrigger>
      <DropdownMenuContent>
        <Copyable text={SAMPLE_TEXT} onCopied={handleCopied}>
          <DropdownMenuItem>
            <DropdownMenuItemIcon>
              <Copy />
            </DropdownMenuItemIcon>
            <DropdownMenuItemText>Copy value</DropdownMenuItemText>
          </DropdownMenuItem>
        </Copyable>
        <DropdownMenuItem>Edit</DropdownMenuItem>
        <DropdownMenuItem>Delete</DropdownMenuItem>
      </DropdownMenuContent>
    </DropdownMenu>
  );
};
```

### Select menu item with toast

A Select option that copies on select — same toast feedback pattern as the
dropdown menu item (feedback rule 3).

```tsx
import { useState } from 'react';
import { createListCollection, Select, SelectButton, SelectContent, SelectOption, SelectOptionText, SelectPositioner } from '@wallarm-org/design-system/Select';
import { toaster } from '@wallarm-org/design-system/Toast';

export const SelectMenuItemWithToast = () => {
  const endpoints = [
    'GET /api/users',
    'POST /api/users',
    'GET /api/users/:id',
    'DELETE /api/users/:id',
  ];

  const collection = createListCollection({
    items: endpoints.map(e => ({ label: e, value: e })),
  });

  const [value, setValue] = useState<string[]>([]);

  const handleValueChange = (details: { value: string[] }) => {
    const selected = details.value[0];
    if (selected) {
      navigator.clipboard.writeText(selected);
      toaster.create({ title: 'Copied', type: 'default', variant: 'simple' });
    }
    // Reset so the select doesn't hold a value — it acts as a copy trigger
    setValue([]);
  };

  return (
    <Select
      collection={collection}
      value={value}
      onValueChange={handleValueChange}
      positioning={{ placement: 'bottom-start' }}
    >
      <SelectButton placeholder='Select endpoint to copy' style={{ width: 280 }} />
      <SelectPositioner>
        <SelectContent>
          {endpoints.map(ep => (
            <SelectOption key={ep} item={{ label: ep, value: ep }}>
              <SelectOptionText>{ep}</SelectOptionText>
            </SelectOption>
          ))}
        </SelectContent>
      </SelectPositioner>
    </Select>
  );
};
```

### All recipes

All recipes side-by-side for comparison. The three feedback types —
in-place swap, tooltip-only, and toast — are shown together.

```tsx
import { Button } from '@wallarm-org/design-system/Button';
import { InlineCodeSnippet } from '@wallarm-org/design-system/CodeSnippet';
import { Copyable, CopyableIcon, CopyableLabel } from '@wallarm-org/design-system/Copyable';
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuItemIcon, DropdownMenuItemText, DropdownMenuTrigger } from '@wallarm-org/design-system/DropdownMenu';
import { Copy } from '@wallarm-org/design-system/icons';
import { HStack, VStack } from '@wallarm-org/design-system/Stack';
import { Text } from '@wallarm-org/design-system/Text';
import { toaster } from '@wallarm-org/design-system/Toast';

export const AllRecipes = () => {
  const handleCopied = () => {
    toaster.create({ title: 'Copied', type: 'default', variant: 'simple' });
  };

  return (
    <VStack align='start' gap={32}>
      <VStack align='start' gap={8}>
        <Text size='xs' color='secondary' weight='medium'>
          Icon button (swap)
        </Text>
        <Copyable text={SAMPLE_TEXT} tooltip>
          <Button variant='ghost' color='neutral' size='small' aria-label='Copy'>
            <CopyableIcon />
          </Button>
        </Copyable>
      </VStack>

      <VStack align='start' gap={8}>
        <Text size='xs' color='secondary' weight='medium'>
          Labelled button (swap)
        </Text>
        <HStack gap={12}>
          <Copyable text={SAMPLE_TEXT} tooltip>
            <Button variant='secondary' size='medium'>
              <CopyableIcon /> <CopyableLabel idle='Copy code' copied='Copied' />
            </Button>
          </Copyable>
        </HStack>
      </VStack>

      <VStack align='start' gap={8}>
        <Text size='xs' color='secondary' weight='medium'>
          Inline code snippet (tooltip only)
        </Text>
        <Text size='sm'>
          Run <InlineCodeSnippet code='npm install' size='md' /> to install.
        </Text>
      </VStack>

      <VStack align='start' gap={8}>
        <Text size='xs' color='secondary' weight='medium'>
          Dropdown menu item (toast)
        </Text>
        <DropdownMenu>
          <DropdownMenuTrigger asChild>
            <Button variant='outline' color='neutral' size='small'>
              Actions
            </Button>
          </DropdownMenuTrigger>
          <DropdownMenuContent>
            <Copyable text={SAMPLE_TEXT} onCopied={handleCopied}>
              <DropdownMenuItem>
                <DropdownMenuItemIcon>
                  <Copy />
                </DropdownMenuItemIcon>
                <DropdownMenuItemText>Copy value</DropdownMenuItemText>
              </DropdownMenuItem>
            </Copyable>
          </DropdownMenuContent>
        </DropdownMenu>
      </VStack>
    </VStack>
  );
};
```

## Props

| Prop       | Type                                                                  | Default | Description                                                                                                                                                                                          |
| ---------- | --------------------------------------------------------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| text \*    | `string \| (() => string)`                                            |         | The text to copy to the clipboard. Pass a function to read the text lazily at click time (e.g. the live document of an editor).                                                                      |
| tooltip    | `string \| boolean \| { idle: string; copied: string; } \| undefined` |         | Show a tooltip with copy feedback. - `true`  — "Click to copy" / "Copied" - `string` — custom idle text; copied text stays "Copied" - `{ idle: string; copied: string }` — fully custom tooltip text |
| onCopied   | `(() => void) \| undefined`                                           |         | Fired after a successful copy. Use for toast feedback.                                                                                                                                               |
| resetDelay | `number \| undefined`                                                 | `2000`  | Time in ms before the `copied` state resets (default: 2000).                                                                                                                                         |

### CopyableIcon

| Prop     | Type                                                                                              | Default | Description |
| -------- | ------------------------------------------------------------------------------------------------- | ------- | ----------- |
| height   | `string \| number \| undefined`                                                                   |         |             |
| id       | `string \| undefined`                                                                             |         |             |
| max      | `string \| number \| undefined`                                                                   |         |             |
| min      | `string \| number \| undefined`                                                                   |         |             |
| name     | `string \| undefined`                                                                             |         |             |
| target   | `string \| undefined`                                                                             |         |             |
| type     | `string \| undefined`                                                                             |         |             |
| width    | `string \| number \| undefined`                                                                   |         |             |
| tabIndex | `number \| undefined`                                                                             |         |             |
| href     | `string \| undefined`                                                                             |         |             |
| onChange | `ChangeEventHandler<T, Element> \| undefined`                                                     |         |             |
| size     | `{ inherit: string; xs: string; sm: string; md: string; lg: string; xl: string; '2xl': string; }` |         |             |
| title    | `string \| undefined`                                                                             |         |             |

### CopyableLabel

| Prop    | Type                  | Default | Description                                             |
| ------- | --------------------- | ------- | ------------------------------------------------------- |
| idle \* | `string`              |         | Label shown in the idle state                           |
| copied  | `string \| undefined` |         | Label shown after a successful copy (default: "Copied") |

## Explorer

