---
title: Clipboard Button
description: Copy-to-clipboard button
visibility: guest
draft: false
---

# Clipboard Button

The `<x-wirekit::clipboard-button>` component copies a value to the clipboard on click and temporarily shows a "Copied!" confirmation. It uses the [Clipboard API](https://developer.mozilla.org/en-US/docs/Web/API/Clipboard_API) and announces the copy action to screen readers via a live region.

## Usage

<!-- markdownlint-disable MD034 -->
:::preview{title="Clipboard Button"}
<x-wirekit::clipboard-button value="https://wirekit.app">
    Copy Link
</x-wirekit::clipboard-button>
:::

Inline with a code snippet:

```blade
<div class="flex items-center justify-between rounded-lg px-3 py-2" style="background: var(--color-wk-bg-muted);">
    <code class="text-sm">composer require pushery/wirekit</code>
    <x-wirekit::clipboard-button value="composer require pushery/wirekit">
        Copy
    </x-wirekit::clipboard-button>
</div>
```

### Custom Confirmation Text

Change the text shown after copying:

:::preview{title="Custom Confirmation Text"}
<x-wirekit::clipboard-button value="npm install wirekit" copiedText="Done!">
    Copy Command
</x-wirekit::clipboard-button>
:::

### Custom Duration

Control how long the "Copied!" state persists (in milliseconds):

:::preview{title="Custom Duration (5s)"}
<x-wirekit::clipboard-button value="secret-token-123" :duration="5000">
    Copy Token
</x-wirekit::clipboard-button>
:::

### Copying Dynamic Values

Use Blade expressions to copy dynamic content:

```blade
<x-wirekit::clipboard-button :value="$user->api_key">
    Copy API Key
</x-wirekit::clipboard-button>
```

### Code Block with Copy

Combine with other components to create a copyable code snippet:

:::preview{title="Code Block with Copy"}
<div style="display: flex; align-items: center; justify-content: space-between; background: var(--color-wk-bg-muted); border-radius: 0.5rem; padding: 0.5rem;">
    <code style="font-family: var(--font-wk-mono); font-size: 0.875rem;">
        composer require pushery/wirekit
    </code>
    <x-wirekit::clipboard-button value="composer require pushery/wirekit">
        Copy
    </x-wirekit::clipboard-button>
</div>
:::

:::source{language="blade"}
<x-wirekit::row justify="between" style="background: var(--color-wk-bg-muted); border-radius: 0.5rem; padding: 0.5rem;">
    <code style="font-family: var(--font-wk-mono); font-size: 0.875rem;">
        composer require pushery/wirekit
    </code>
    <x-wirekit::clipboard-button value="composer require pushery/wirekit">
        Copy
    </x-wirekit::clipboard-button>
</x-wirekit::row>
:::

## Visual Behavior

1. **Default state** — shows a clipboard icon + your slot content (e.g., "Copy Link")
2. **After click** — icon swaps to a green checkmark, label changes to `copiedText`
3. **After duration** — reverts to the default state automatically

The icon swap is handled by Alpine's `x-show` directives. The checkmark icon uses `--color-wk-success-text` for the green color.

## Requirements

The clipboard button uses the [Clipboard API](https://developer.mozilla.org/en-US/docs/Web/API/Clipboard_API) (`navigator.clipboard.writeText()`), which requires:

- **HTTPS** or **localhost** — the Clipboard API is only available in secure contexts
- **User gesture** — the copy happens inside a click handler, which satisfies the browser's user activation requirement

If neither condition is met, the copy will silently fail. All modern browsers (Chrome, Firefox, Safari, Edge) support the Clipboard API.

## Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `value` | `string` | `''` | The text to copy to the clipboard |
| `copiedText` | `string` | `'Copied!'` | Label shown temporarily after copying |
| `duration` | `int` | `2000` | How long (ms) the "Copied!" state persists before reverting |
| `iconOnly` | `bool` | `false` | Render a bare icon-only button (no border/label) — gray glyph that pops green on copy. Requires `aria-label`. |
| `scope` | `string\|null` | `null` | Scoped personalization key |

## Accessibility

- The button is a native `<button type="button">` — fully keyboard-accessible
- Icons: `aria-hidden="true"` on both SVGs (decorative — the text label is the accessible name)
- Live region: `role="status"` + `aria-live="polite"` announces "Copied to clipboard" to screen readers when the copy succeeds
- Focus ring visible via `focus-visible:ring`

::: tip
The slot content (e.g., "Copy Link") serves as the button's accessible name. If you need a different accessible name, pass an `aria-label` attribute.
:::

## Keyboard Interaction

| Key | Action |
|-----|--------|
| `Tab` | Move focus to the button |
| `Enter` / `Space` | Activate the button |

## Pitfalls

- **Don't bind `wire:click` on the button — use the component's built-in `:value` prop.** The Alpine handler writes via the Clipboard API; a `wire:click` server roundtrip would race the clipboard write.

## Design Tokens

| Token | Used for |
| --- | --- |
| `--font-wk-sans` | Button font family |
| `--font-wk-body-weight` | Font weight |
| `--text-wk-md` | Font size |
| `--color-wk-text` | Default label text |
| `--color-wk-success-text` | Copied checkmark color |
| `--color-wk-bg-elevated` | Button background |
| `--color-wk-bg-subtle` | Hover background |
| `--color-wk-border` | Button border |
| `--color-wk-ring` | Focus ring |
| `--ring-wk-width` | Focus ring width |
| `--border-wk-width` | Border width |
| `--radius-wk-md` | Border radius |
| `--shadow-wk-sm` | Subtle shadow |
| `--gap-wk-sm` | Icon-to-label gap |
| `--padding-wk-x-md` / `--padding-wk-y-sm` | Button padding |
| `--transition-wk-duration` / `--transition-wk-easing` | Hover / icon-swap transition |

## Personalization

Override classes globally via `WireKit::personalize()`:

```php
use Pushery\WireKit\WireKit;

WireKit::personalize('clipboard-button', [
    'base' => 'inline-flex items-center gap-2 px-4 py-2 text-sm bg-blue-600 text-white rounded-md',
]);
```

## Further Reading

- [MDN: Clipboard API](https://developer.mozilla.org/en-US/docs/Web/API/Clipboard_API) — the browser API used for copying
- [MDN: `navigator.clipboard.writeText()`](https://developer.mozilla.org/en-US/docs/Web/API/Clipboard/writeText) — the specific method called
- [MDN: `role="status"`](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/status_role) — live region role for the copy announcement
- [Can I Use: Clipboard API](https://caniuse.com/async-clipboard) — browser support table
