Skip to content

Copy Button

Experimental Alpha

This library is a work-in-progress. We are releasing it early to gather feedback, but it is not ready for production.

An accessible button component that copies text to the clipboard with visual feedback. The CopyButton automatically toggles between copy and checkmark icons and provides customizable success messaging.

Examples

Vue
Lit
React
Live Preview

Basic Copy Button

Projected Icons

Sizes & Variants

Inline Code Example

npm install agnosticui-core

Copy From Input

Copy the value from the input using reactive binding.

View Vue Code
```vue
<template>
  <section>
    <div class="mbe4">
      <h2>Basic Copy Button</h2>
    </div>

    <div class="stacked-mobile mbe4">
      <VueCopyButton
        text="https://agnosticui.com"
        label="Copy URL"
      />
    </div>

    <div class="mbe4">
      <h2>Projected Icons</h2>
    </div>

    <div class="stacked-mobile mbe4">
      <VueCopyButton
        text="Projected Icons Example"
        label="Projected Icons"
      >
        <template #icon-copy>
          <svg
            width="100%"
            height="100%"
            viewBox="0 0 24 24"
            fill="none"
            xmlns="http://www.w3.org/2000/svg"
          >
            <path
              d="M7.5 3H14.6C16.8402 3 17.9603 3 18.816 3.43597C19.5686 3.81947 20.1805 4.43139 20.564 5.18404C21 6.03969 21 7.15979 21 9.4V16.5M6.2 21H14.3C15.4201 21 15.9802 21 16.408 20.782C16.7843 20.5903 17.0903 20.2843 17.282 19.908C17.5 19.4802 17.5 18.9201 17.5 17.8V9.7C17.5 8.57989 17.5 8.01984 17.282 7.59202C17.0903 7.21569 16.7843 6.90973 16.408 6.71799C15.9802 6.5 15.4201 6.5 14.3 6.5H6.2C5.0799 6.5 4.51984 6.5 4.09202 6.71799C3.71569 6.90973 3.40973 7.21569 3.21799 7.59202C3 8.01984 3 8.57989 3 9.7V17.8C3 18.9201 3 19.4802 3.21799 19.908C3.40973 20.2843 3.71569 20.5903 4.09202 20.782C4.51984 21 5.0799 21 6.2 21Z"
              stroke="currentColor"
              stroke-width="2"
              stroke-linecap="round"
              stroke-linejoin="round"
            />
          </svg>
        </template>
        <template #icon-copied>
          <svg
            width="100%"
            height="100%"
            viewBox="0 0 24 24"
            fill="none"
            xmlns="http://www.w3.org/2000/svg"
          >
            <path
              d="M20 6L9 17L4 12"
              stroke="currentColor"
              stroke-width="2"
              stroke-linecap="round"
              stroke-linejoin="round"
            />
          </svg>
        </template>
      </VueCopyButton>
    </div>

    <div class="mbe4">
      <h2>Sizes & Variants</h2>
    </div>
    <div class="stacked-mobile mbe4">
      <VueCopyButton
        text="Copy this"
        size="xs"
      />
      <VueCopyButton
        text="Copy this"
        size="sm"
      />
      <VueCopyButton
        text="Copy this"
        size="md"
      />
      <VueCopyButton
        text="Copy this"
        size="lg"
      />
      <VueCopyButton
        text="Copy this"
        size="xl"
      />
    </div>

    <div class="stacked-mobile mbe4">
      <VueCopyButton
        text="Copy primary"
        variant="primary"
      />
      <VueCopyButton
        text="Copy success"
        variant="success"
      />
      <VueCopyButton
        text="Copy warning"
        variant="warning"
      />
      <VueCopyButton
        text="Copy danger"
        variant="danger"
      />
      <VueCopyButton
        text="Copy ghost"
        variant="ghost"
      />
    </div>

    <div class="mbe4">
      <h2>Inline Code Example</h2>
    </div>
    <div class="code-example mbe4">
      <pre><code>npm install agnosticui-core</code></pre>
      <VueCopyButton
        class="code-copy"
        text="npm install agnosticui-core"
        label="Copy install command"
        size="sm"
        variant="ghost"
      ></VueCopyButton>
    </div>

    <div class="mbe4">
      <h2>Copy From Input</h2>
      <p
        class="mbe2"
        style="color: var(--ag-text-secondary); font-size: 0.875rem;"
      >Copy the value from the input using reactive binding.</p>
    </div>
    <div class="stacked-mobile mbe4">
      <div style="display:flex;gap:12px;align-items:center;flex:1;">
        <input
          v-model="inputValue"
          aria-label="Copy input"
          style="padding:8px;flex:1;border-radius:6px;border:1px solid var(--ag-border)"
        />
        <VueCopyButton
          :text="inputValue"
          label="Copy input"
        />
      </div>
    </div>

  </section>
</template>

<script>
import { VueCopyButton } from "agnosticui-core/copy-button/vue";
import { Clipboard, Check } from "lucide-vue-next";

export default {
  name: "CopyButtonExamples",
  components: {
    VueCopyButton,
    Clipboard,
    Check,
  },
  data() {
    return {
      inputValue: "https://agnosticui.com/components/copybutton",
    };
  },
};
</script>

<style scoped>
.stacked-mobile {
  align-items: center;
}

.code-example {
  position: relative;
  background: var(--ag-background-secondary);
  padding: var(--ag-space-4);
  border-radius: var(--ag-radius-md);
}

.code-copy {
  position: absolute;
  top: var(--ag-space-2);
  right: var(--ag-space-2);
}
</style>
Live Preview
View Lit / Web Component Code
import { LitElement, html } from 'lit';
import 'agnosticui-core/copy-button';

export class CopyButtonLitExamples extends LitElement {
  // Render in light DOM to access global utility classes
  createRenderRoot() {
    return this;
  }

  constructor() {
    super();
    this.inputValue = 'https://agnosticui.com/components/copybutton';
  }

  handleInputChange(e) {
    this.inputValue = e.target.value;
    this.requestUpdate();
  }

  render() {
    return html`
      <section>
        <!-- Basic Copy Button -->
        <div class="mbe4">
          <h2>Basic Copy Button</h2>
        </div>

        <div class="stacked-mobile mbe4">
          <ag-copy-button
            text="https://agnosticui.com"
            label="Copy URL"
          ></ag-copy-button>
        </div>

        <!-- Projected Icons -->
        <div class="mbe4">
          <h2>Projected Icons</h2>
        </div>

        <div class="stacked-mobile mbe4">
          <ag-copy-button
            text="Projected Icons Example"
            label="Projected Icons"
          >
            <svg
              slot="icon-copy"
              width="100%"
              height="100%"
              viewBox="0 0 24 24"
              fill="none"
              xmlns="http://www.w3.org/2000/svg"
            >
              <path
                d="M7.5 3H14.6C16.8402 3 17.9603 3 18.816 3.43597C19.5686 3.81947 20.1805 4.43139 20.564 5.18404C21 6.03969 21 7.15979 21 9.4V16.5M6.2 21H14.3C15.4201 21 15.9802 21 16.408 20.782C16.7843 20.5903 17.0903 20.2843 17.282 19.908C17.5 19.4802 17.5 18.9201 17.5 17.8V9.7C17.5 8.57989 17.5 8.01984 17.282 7.59202C17.0903 7.21569 16.7843 6.90973 16.408 6.71799C15.9802 6.5 15.4201 6.5 14.3 6.5H6.2C5.0799 6.5 4.51984 6.5 4.09202 6.71799C3.71569 6.90973 3.40973 7.21569 3.21799 7.59202C3 8.01984 3 8.57989 3 9.7V17.8C3 18.9201 3 19.4802 3.21799 19.908C3.40973 20.2843 3.71569 20.5903 4.09202 20.782C4.51984 21 5.0799 21 6.2 21Z"
                stroke="currentColor"
                stroke-width="2"
                stroke-linecap="round"
                stroke-linejoin="round"
              />
            </svg>
            <svg
              slot="icon-copied"
              width="100%"
              height="100%"
              viewBox="0 0 24 24"
              fill="none"
              xmlns="http://www.w3.org/2000/svg"
            >
              <path
                d="M20 6L9 17L4 12"
                stroke="currentColor"
                stroke-width="2"
                stroke-linecap="round"
                stroke-linejoin="round"
              />
            </svg>
          </ag-copy-button>
        </div>

        <!-- Sizes & Variants -->
        <div class="mbe4">
          <h2>Sizes & Variants</h2>
        </div>
        <div class="stacked-mobile mbe4">
          <ag-copy-button text="Copy this" size="xs"></ag-copy-button>
          <ag-copy-button text="Copy this" size="sm"></ag-copy-button>
          <ag-copy-button text="Copy this" size="md"></ag-copy-button>
          <ag-copy-button text="Copy this" size="lg"></ag-copy-button>
          <ag-copy-button text="Copy this" size="xl"></ag-copy-button>
        </div>

        <div class="stacked-mobile mbe4">
          <ag-copy-button text="Copy primary" variant="primary"></ag-copy-button>
          <ag-copy-button text="Copy success" variant="success"></ag-copy-button>
          <ag-copy-button text="Copy warning" variant="warning"></ag-copy-button>
          <ag-copy-button text="Copy danger" variant="danger"></ag-copy-button>
          <ag-copy-button text="Copy ghost" variant="ghost"></ag-copy-button>
        </div>

        <!-- Inline Code Example -->
        <div class="mbe4">
          <h2>Inline Code Example</h2>
        </div>
        <div class="code-example mbe4">
          <pre><code>npm install agnosticui-core</code></pre>
          <ag-copy-button
            class="code-copy"
            text="npm install agnosticui-core"
            label="Copy install command"
            size="sm"
            variant="ghost"
          ></ag-copy-button>
        </div>

        <!-- Copy From Input -->
        <div class="mbe4">
          <h2>Copy From Input</h2>
          <p class="mbe2" style="color: var(--ag-text-secondary); font-size: 0.875rem;">
            Copy the value from the input using reactive binding.
          </p>
        </div>
        <div class="stacked-mobile mbe4">
          <div style="display:flex;gap:12px;align-items:center;flex:1;">
            <input
              .value=${this.inputValue}
              @input=${this.handleInputChange}
              aria-label="Copy input"
              style="padding:8px;flex:1;border-radius:6px;border:1px solid var(--ag-border)"
            />
            <ag-copy-button
              text=${this.inputValue}
              label="Copy input"
            ></ag-copy-button>
          </div>
        </div>
      </section>
    `;
  }
}

// Register the custom element
customElements.define('copybutton-lit-examples', CopyButtonLitExamples);

Interactive Preview: Click the "Open in StackBlitz" button below to see this example running live in an interactive playground.

View React Code
import { useState } from "react";
import { ReactCopyButton } from "agnosticui-core/copy-button/react";

export default function CopyButtonReactExamples() {
  const [inputValue, setInputValue] = useState("https://agnosticui.com/components/copybutton");

  const handleInputChange = (e) => {
    setInputValue(e.target.value);
  };

  return (
    <section>
      {/* Basic Copy Button */}
      <div className="mbe4">
        <h2>Basic Copy Button</h2>
      </div>

      <div className="stacked-mobile mbe4">
        <ReactCopyButton
          text="https://agnosticui.com"
          label="Copy URL"
        />
      </div>

      {/* Projected Icons */}
      <div className="mbe4">
        <h2>Projected Icons</h2>
      </div>

      <div className="stacked-mobile mbe4">
        <ReactCopyButton
          text="Projected Icons Example"
          label="Projected Icons"
          iconCopy={
            <svg
              width="100%"
              height="100%"
              viewBox="0 0 24 24"
              fill="none"
              xmlns="http://www.w3.org/2000/svg"
            >
              <path
                d="M7.5 3H14.6C16.8402 3 17.9603 3 18.816 3.43597C19.5686 3.81947 20.1805 4.43139 20.564 5.18404C21 6.03969 21 7.15979 21 9.4V16.5M6.2 21H14.3C15.4201 21 15.9802 21 16.408 20.782C16.7843 20.5903 17.0903 20.2843 17.282 19.908C17.5 19.4802 17.5 18.9201 17.5 17.8V9.7C17.5 8.57989 17.5 8.01984 17.282 7.59202C17.0903 7.21569 16.7843 6.90973 16.408 6.71799C15.9802 6.5 15.4201 6.5 14.3 6.5H6.2C5.0799 6.5 4.51984 6.5 4.09202 6.71799C3.71569 6.90973 3.40973 7.21569 3.21799 7.59202C3 8.01984 3 8.57989 3 9.7V17.8C3 18.9201 3 19.4802 3.21799 19.908C3.40973 20.2843 3.71569 20.5903 4.09202 20.782C4.51984 21 5.0799 21 6.2 21Z"
                stroke="currentColor"
                strokeWidth="2"
                strokeLinecap="round"
                strokeLinejoin="round"
              />
            </svg>
          }
          iconCopied={
            <svg
              width="100%"
              height="100%"
              viewBox="0 0 24 24"
              fill="none"
              xmlns="http://www.w3.org/2000/svg"
            >
              <path
                d="M20 6L9 17L4 12"
                stroke="currentColor"
                strokeWidth="2"
                strokeLinecap="round"
                strokeLinejoin="round"
              />
            </svg>
          }
        />
      </div>

      {/* Sizes & Variants */}
      <div className="mbe4">
        <h2>Sizes & Variants</h2>
      </div>
      <div className="stacked-mobile mbe4">
        <ReactCopyButton text="Copy this" size="xs" />
        <ReactCopyButton text="Copy this" size="sm" />
        <ReactCopyButton text="Copy this" size="md" />
        <ReactCopyButton text="Copy this" size="lg" />
        <ReactCopyButton text="Copy this" size="xl" />
      </div>

      <div className="stacked-mobile mbe4">
        <ReactCopyButton text="Copy primary" variant="primary" />
        <ReactCopyButton text="Copy success" variant="success" />
        <ReactCopyButton text="Copy warning" variant="warning" />
        <ReactCopyButton text="Copy danger" variant="danger" />
        <ReactCopyButton text="Copy ghost" variant="ghost" />
      </div>

      {/* Inline Code Example */}
      <div className="mbe4">
        <h2>Inline Code Example</h2>
      </div>
      <div className="code-example mbe4">
        <pre><code>npm install agnosticui-core</code></pre>
        <ReactCopyButton
          className="code-copy"
          text="npm install agnosticui-core"
          label="Copy install command"
          size="sm"
          variant="ghost"
        />
      </div>

      {/* Copy From Input */}
      <div className="mbe4">
        <h2>Copy From Input</h2>
        <p className="mbe2" style={{ color: "var(--ag-text-secondary)", fontSize: "0.875rem" }}>
          Copy the value from the input using reactive binding.
        </p>
      </div>
      <div className="stacked-mobile mbe4">
        <div style={{ display: "flex", gap: "12px", alignItems: "center", flex: 1 }}>
          <input
            value={inputValue}
            onChange={handleInputChange}
            aria-label="Copy input"
            style={{
              padding: "8px",
              flex: 1,
              borderRadius: "6px",
              border: "1px solid var(--ag-border)"
            }}
          />
          <ReactCopyButton
            text={inputValue}
            label="Copy input"
          />
        </div>
      </div>
    </section>
  );
}
Open in StackBlitz

Basic Usage

TIP

The framework examples below import AgnosticUI as an npm package. Alternatively, you can use the CLI for complete control, AI/LLM visibility, and full code ownership:

bash
npx ag init --framework FRAMEWORK # react, vue, lit, svelte, etc.
npx ag add Copybutton

The CLI copies source code directly into your project, giving you full visibility and control. After running npx ag add, you'll receive exact import instructions.

Lit (Web Components)
html
<script type="module">
  import 'agnosticui-core/copy-button';
</script>

<ag-copy-button
  text="npm install agnosticui-core"
  label="Copy install command"
></ag-copy-button>

<ag-copy-button
  text="console.log('Hello, AgnosticUI!');"
  label="Copy code snippet"
  success-label="Code copied!"
></ag-copy-button>

<ag-copy-button
  id="copy-btn"
  text="Event handling example"
  label="Copy with event"
></ag-copy-button>

<script>
  const copyBtn = document.querySelector('#copy-btn');
  copyBtn?.addEventListener('copy', (e) => {
    console.log('Copied to clipboard:', e.detail.text);
  });
</script>
Vue
vue
<template>
  <section>
    <VueCopyButton
      text="npm install agnosticui-core"
      label="Copy install command"
    />

    <VueCopyButton
      id="vue-copy-btn"
      text="Event handling example"
      label="Copy with event"
    />
  </section>
</template>

<script>
import VueCopyButton from 'agnosticui-core/copy-button/vue'

export default {
  components: { VueCopyButton },
  mounted() {
    const copyBtn = document.querySelector('#vue-copy-btn');
    copyBtn?.addEventListener('copy', (e) => {
      console.log('Copied to clipboard (Vue):', e.detail.text);
    });
  }
}
</script>
React
tsx
import React from 'react';
import { ReactCopyButton } from 'agnosticui-core/copy-button/react';

export default function Example() {
  return (
    <div>
      <ReactCopyButton text="npm install agnosticui-core" label="Copy install command" />

      <ReactCopyButton
        text="Event handling example"
        label="Copy with event"
        onCopy={(e: any) => console.log('Copied to clipboard (React):', e.detail?.text)}
      />
    </div>
  );
}

Custom Icons

The CopyButton allows you to provide custom SVG icons for both the copy and copied states while maintaining default fallbacks:

html
<ag-copy-button
  text="Uses default Material Design icons"
  label="Copy with defaults"
></ag-copy-button>

<ag-copy-button
  text="Both icons customized"
  label="Copy with custom icons"
>
  <svg slot="icon-copy" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" stroke-width="1.5">
    <path d="M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1z" />
    <rect x="8" y="5" width="11" height="14" rx="2" ry="2" stroke="currentColor" fill="none" />
    <path d="M8 7h8" stroke="currentColor" />
  </svg>

  <svg slot="icon-copied" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="20" height="20" fill="#16A34A" stroke="none">
    <circle cx="12" cy="12" r="10" />
    <path d="M9 12.5l2 2 4-5" fill="none" stroke="#fff" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" />
  </svg>
</ag-copy-button>

Using Icon Libraries

You can use any SVG icon library with the custom icon slots:

html
<ag-copy-button text="Heroicons example" label="Copy">
  <svg slot="icon-copy" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
    <path stroke-linecap="round" stroke-linejoin="round" d="M15.75 17.25v3.375c0 .621-.504 1.125-1.125 1.125h-9.75a1.125 1.125 0 01-1.125-1.125V7.875c0-.621.504-1.125 1.125-1.125H6.75a9.06 9.06 0 011.5.124m7.5 10.376h3.375c.621 0 1.125-.504 1.125-1.125V11.25c0-4.46-3.243-8.161-7.5-8.876a9.06 9.06 0 00-1.5-.124H9.375c-.621 0-1.125.504-1.125 1.125v3.5m7.5 10.375H9.375a1.125 1.125 0 01-1.125-1.125v-9.25m12 6.625v-1.875a3.375 3.375 0 00-3.375-3.375h-1.5a1.125 1.125 0 01-1.125-1.125v-1.5a3.375 3.375 0 00-3.375-3.375H9.75" />
  </svg>
  <svg slot="icon-copied" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
    <path stroke-linecap="round" stroke-linejoin="round" d="M9 12.75L11.25 15 15 9.75M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
  </svg>
</ag-copy-button>

<ag-copy-button text="Feather Icons example" label="Copy">
  <svg slot="icon-copy" xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
    <rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect>
    <path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path>
  </svg>
  <svg slot="icon-copied" xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
    <path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"></path>
    <polyline points="22 4 12 14.01 9 11.01"></polyline>
  </svg>
</ag-copy-button>

Props

PropTypeDefaultDescription
textstring''Required. The text to copy to the clipboard.
labelstring'Copy to clipboard'Accessible label for the button (aria-label). Announced by screen readers.
successLabelstring'Copied!'Label to show when the text has been successfully copied.
size'xs' | 'sm' | 'md' | 'lg' | 'xl''md'Size of the button. Controls button dimensions and icon size.
variant'primary' | 'secondary' | 'success' | 'warning' | 'danger' | 'ghost' | 'monochrome''ghost'Visual style variant. Inherits from IconButton styling.

Slots

SlotDescription
icon-copyCustom SVG icon for the default copy state. Falls back to a copy icon if not provided.
icon-copiedCustom SVG icon for the success/copied state. Falls back to checkmark icon if not provided.

Note: If you provide custom icons, you must supply both the icon-copy and icon-copied slots together. Providing only one will throw a runtime error.

Events

EventDetailDescription
copy{ text: string }Fired when text is successfully copied to the clipboard. Provides the copied text in the event detail.

Event Handling Examples

html
<ag-copy-button id="event-example" text="Event example"></ag-copy-button>

<script>
  const btn = document.querySelector('#event-example');
  btn.addEventListener('copy', (e) => {
    console.log('Copied:', e.detail.text);
    showToast(`Copied: ${e.detail.text}`);
  });
</script>

<script>
  const copyBtn = document.querySelector('#multi-handler');

  copyBtn.addEventListener('copy', (e) => {
    trackEvent('copy_button', { text: e.detail.text });
  });

  copyBtn.addEventListener('copy', (e) => {
    updateCopyCount();
  });
</script>

Accessibility

The CopyButton is built on top of IconButton and implements proper accessibility:

  • Uses semantic <button> element
  • Provides clear accessible labels via aria-label
  • Announces state changes to screen readers (copy → copied)
  • Keyboard accessible (Space and Enter keys)
  • Clear focus indicators for keyboard navigation
  • Minimum 44px touch target for mobile accessibility (WCAG 2.1 Level AAA)

Success Feedback

The success state provides feedback through:

  1. Visual: Icon changes from copy to checkmark
  2. Text: Label updates from "Copy to clipboard" to "Copied!"
  3. Assistive tech: Screen readers announce the new label
  4. Timing: Automatically reverts after 1 second

Common Patterns

Code Snippets

Use CopyButton alongside code blocks in documentation:

html
<div class="code-example">
  <pre><code>npm install agnosticui-core</code></pre>
  <ag-copy-button
    text="npm install agnosticui-core"
    label="Copy install command"
    size="sm"
    variant="ghost"
  ></ag-copy-button>
</div>

<style>
  .code-example {
    position: relative;
    background: #f3f4f6;
    padding: var(--ag-space-4);
    border-radius: var(--ag-radius);
  }

  .code-example ag-copy-button {
    position: absolute;
    top: var(--ag-space-2);
    right: var(--ag-space-2);
  }
</style>

API Keys and Tokens

Copy sensitive information with visual confirmation:

html
<div class="token-display">
  <code id="api-token">sk_test_abc123xyz789...</code>
  <ag-copy-button
    text="sk_test_abc123xyz789..."
    label="Copy API token"
    success-label="Token copied!"
    variant="monochrome"
    size="sm"
  ></ag-copy-button>
</div>

<script>
  const copyBtn = document.querySelector('.token-display ag-copy-button');
  copyBtn.addEventListener('copy', () => {
    console.log('API token copied at:', new Date().toISOString());
  });
</script>

Share URLs

Make sharing links easier:

html
<div class="share-section">
  <label for="share-url">Share this page:</label>
  <div class="share-input-group">
    <input
      id="share-url"
      type="text"
      readonly
      value="https://agnosticui.com/components/copybutton"
    />
    <ag-copy-button
      text="https://agnosticui.com/components/copybutton"
      label="Copy share link"
      success-label="Link copied!"
      variant="primary"
    ></ag-copy-button>
  </div>
</div>

Integration with Toast Notifications

Combine with toast notifications for enhanced feedback:

html
<ag-copy-button
  id="toast-copy"
  text="Content to copy"
  label="Copy"
></ag-copy-button>

<script>
  import 'agnosticui-core/toast';

  const btn = document.querySelector('#toast-copy');
  const toastContainer = document.querySelector('ag-toast-container');

  btn.addEventListener('copy', (e) => {
    const toast = document.createElement('ag-toast');
    toast.type = 'success';
    toast.textContent = `Copied: ${e.detail.text}`;
    toastContainer.appendChild(toast);
  });
</script>

Browser Support

The CopyButton uses the Clipboard API which is supported in all modern browsers:

  • Chrome/Edge 66+
  • Firefox 63+
  • Safari 13.1+

For older browsers, the copy operation will fail gracefully and log an error to the console.

Best Practices

  1. Provide clear context - Use descriptive labels that indicate what's being copied
  2. Position strategically - Place copy buttons near the content they copy
  3. Use appropriate variants - Ghost or monochrome work well in most contexts
  4. Consider mobile - The default sizes work well on touch devices
  5. Track failures - Listen for console errors if clipboard access fails
  6. Combine with feedback - Consider adding toast notifications for important copy actions
  7. Secure sensitive data - Log or audit when sensitive information is copied

When to Use

Use CopyButton when:

  • Users need to copy code snippets, commands, or text
  • You want to reduce friction in workflows (API keys, share links)
  • Space is limited and you need a compact copy solution
  • You have documentation or technical content

Consider alternatives when:

  • The content is very long (let users select and copy themselves)
  • Copy functionality isn't the primary action
  • You need more context than a button provides