Components
Clipboard
Copy buttons and copy tags: copy text, an input's value or an element's text, and show a green tick for a moment, on every browser.
<button type="button" class="btn btn-outline clipboard" data-clipboard data-clipboard-text="npm i htmx-ui">
<span class="clipboard-idle"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4" aria-hidden="true"><rect width="14" height="14" x="8" y="8" rx="2"/><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/></svg> Copy</span>
<span class="clipboard-done"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4" aria-hidden="true"><path d="M20 6 9 17l-5-5"/></svg> Copied</span>
</button>
<button type="button" class="btn btn-outline btn-icon clipboard" data-clipboard data-clipboard-text="npm i htmx-ui" aria-label="Copy">
<span class="clipboard-idle"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4" aria-hidden="true"><rect width="14" height="14" x="8" y="8" rx="2"/><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/></svg></span>
<span class="clipboard-done"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4" aria-hidden="true"><path d="M20 6 9 17l-5-5"/></svg></span>
</button>
<button type="button" class="clipboard-tag" data-clipboard aria-label="Copy npm i htmx-ui">
<code data-clipboard-content>npm i htmx-ui</code>
<span class="clipboard" aria-hidden="true"><span class="clipboard-idle"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4" aria-hidden="true"><rect width="14" height="14" x="8" y="8" rx="2"/><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/></svg></span><span class="clipboard-done"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4" aria-hidden="true"><path d="M20 6 9 17l-5-5"/></svg></span></span>
</button>
Markup#
- Any button with
data-clipboardcopies when clicked. Say what withdata-clipboard-text(see What it copies). - Add
.clipboardand put both of its looks inside:.clipboard-idle(a copy icon, a label or both) and.clipboard-done(a tick, "Copied"). - After a copy the button gets
data-copiedfor two seconds, which shows.clipboard-donewith a green tick. The two looks share one space, so the button keeps its width when "Copy" becomes "Copied". - An icon-only button needs
aria-label="Copy"(or "Copy link", "Copy API key"…).
Screen readers hear "Copied" (or "Copy failed") through a polite live region, because a button's changed text isn't
read out by itself. Set data-clipboard-announce to say something else, and
data-clipboard-timeout (ms) to keep the tick longer.
Icon, label or both#
Leave out what you don't need: the icons, the labels, or one of each.
<button type="button" class="btn btn-outline clipboard" data-clipboard data-clipboard-text="Icon and label">
<span class="clipboard-idle"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4" aria-hidden="true"><rect width="14" height="14" x="8" y="8" rx="2"/><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/></svg>Copy</span>
<span class="clipboard-done"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4" aria-hidden="true"><path d="M20 6 9 17l-5-5"/></svg>Copied</span>
</button>
<button type="button" class="btn btn-outline btn-icon clipboard" data-clipboard data-clipboard-text="Icon only" aria-label="Copy">
<span class="clipboard-idle"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4" aria-hidden="true"><rect width="14" height="14" x="8" y="8" rx="2"/><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/></svg></span>
<span class="clipboard-done"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4" aria-hidden="true"><path d="M20 6 9 17l-5-5"/></svg></span>
</button>
<button type="button" class="btn btn-outline clipboard" data-clipboard data-clipboard-text="Label only">
<span class="clipboard-idle">Copy</span>
<span class="clipboard-done">Copied</span>
</button>
<button type="button" class="btn btn-outline clipboard" data-clipboard data-clipboard-text="Custom labels">
<span class="clipboard-idle"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4" aria-hidden="true"><rect width="14" height="14" x="8" y="8" rx="2"/><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/></svg>Copy link</span>
<span class="clipboard-done"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4" aria-hidden="true"><path d="M20 6 9 17l-5-5"/></svg>Link copied</span>
</button>
Variants#
Every button variant works. The tick is green on outline, ghost, secondary and link buttons; on a filled primary or danger button it keeps the button's text colour, so it stays readable.
<button type="button" class="btn btn-outline clipboard" data-clipboard data-clipboard-text="Outline">
<span class="clipboard-idle"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4" aria-hidden="true"><rect width="14" height="14" x="8" y="8" rx="2"/><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/></svg>Copy</span>
<span class="clipboard-done"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4" aria-hidden="true"><path d="M20 6 9 17l-5-5"/></svg>Copied</span>
</button>
<button type="button" class="btn btn-secondary clipboard" data-clipboard data-clipboard-text="Secondary">
<span class="clipboard-idle"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4" aria-hidden="true"><rect width="14" height="14" x="8" y="8" rx="2"/><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/></svg>Copy</span>
<span class="clipboard-done"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4" aria-hidden="true"><path d="M20 6 9 17l-5-5"/></svg>Copied</span>
</button>
<button type="button" class="btn btn-ghost clipboard" data-clipboard data-clipboard-text="Ghost">
<span class="clipboard-idle"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4" aria-hidden="true"><rect width="14" height="14" x="8" y="8" rx="2"/><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/></svg>Copy</span>
<span class="clipboard-done"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4" aria-hidden="true"><path d="M20 6 9 17l-5-5"/></svg>Copied</span>
</button>
<button type="button" class="btn btn-primary clipboard" data-clipboard data-clipboard-text="Primary">
<span class="clipboard-idle"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4" aria-hidden="true"><rect width="14" height="14" x="8" y="8" rx="2"/><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/></svg>Copy</span>
<span class="clipboard-done"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4" aria-hidden="true"><path d="M20 6 9 17l-5-5"/></svg>Copied</span>
</button>
<button type="button" class="btn btn-link clipboard" data-clipboard data-clipboard-text="Link">
<span class="clipboard-idle"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4" aria-hidden="true"><rect width="14" height="14" x="8" y="8" rx="2"/><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/></svg>Copy</span>
<span class="clipboard-done"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4" aria-hidden="true"><path d="M20 6 9 17l-5-5"/></svg>Copied</span>
</button>
<button type="button" class="btn btn-outline btn-icon clipboard" data-clipboard data-clipboard-text="Outline" aria-label="Copy">
<span class="clipboard-idle"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4" aria-hidden="true"><rect width="14" height="14" x="8" y="8" rx="2"/><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/></svg></span>
<span class="clipboard-done"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4" aria-hidden="true"><path d="M20 6 9 17l-5-5"/></svg></span>
</button>
<button type="button" class="btn btn-secondary btn-icon clipboard" data-clipboard data-clipboard-text="Secondary" aria-label="Copy">
<span class="clipboard-idle"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4" aria-hidden="true"><rect width="14" height="14" x="8" y="8" rx="2"/><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/></svg></span>
<span class="clipboard-done"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4" aria-hidden="true"><path d="M20 6 9 17l-5-5"/></svg></span>
</button>
<button type="button" class="btn btn-ghost btn-icon clipboard" data-clipboard data-clipboard-text="Ghost" aria-label="Copy">
<span class="clipboard-idle"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4" aria-hidden="true"><rect width="14" height="14" x="8" y="8" rx="2"/><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/></svg></span>
<span class="clipboard-done"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4" aria-hidden="true"><path d="M20 6 9 17l-5-5"/></svg></span>
</button>
<button type="button" class="btn btn-primary btn-icon clipboard" data-clipboard data-clipboard-text="Primary" aria-label="Copy">
<span class="clipboard-idle"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4" aria-hidden="true"><rect width="14" height="14" x="8" y="8" rx="2"/><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/></svg></span>
<span class="clipboard-done"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4" aria-hidden="true"><path d="M20 6 9 17l-5-5"/></svg></span>
</button>
<button type="button" class="btn btn-outline btn-icon btn-rounded clipboard" data-clipboard data-clipboard-text="Rounded" aria-label="Copy">
<span class="clipboard-idle"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4" aria-hidden="true"><rect width="14" height="14" x="8" y="8" rx="2"/><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/></svg></span>
<span class="clipboard-done"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4" aria-hidden="true"><path d="M20 6 9 17l-5-5"/></svg></span>
</button>
Sizes#
The button sizes: .btn-xs, .btn-sm, default and .btn-lg, with or without .btn-icon.
<div class="flex items-center gap-3">
<button type="button" class="btn btn-outline btn-xs clipboard" data-clipboard data-clipboard-text="xs">
<span class="clipboard-idle"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4" aria-hidden="true"><rect width="14" height="14" x="8" y="8" rx="2"/><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/></svg>Copy</span>
<span class="clipboard-done"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4" aria-hidden="true"><path d="M20 6 9 17l-5-5"/></svg>Copied</span>
</button>
<button type="button" class="btn btn-outline btn-sm clipboard" data-clipboard data-clipboard-text="sm">
<span class="clipboard-idle"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4" aria-hidden="true"><rect width="14" height="14" x="8" y="8" rx="2"/><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/></svg>Copy</span>
<span class="clipboard-done"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4" aria-hidden="true"><path d="M20 6 9 17l-5-5"/></svg>Copied</span>
</button>
<button type="button" class="btn btn-outline clipboard" data-clipboard data-clipboard-text="default">
<span class="clipboard-idle"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4" aria-hidden="true"><rect width="14" height="14" x="8" y="8" rx="2"/><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/></svg>Copy</span>
<span class="clipboard-done"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4" aria-hidden="true"><path d="M20 6 9 17l-5-5"/></svg>Copied</span>
</button>
<button type="button" class="btn btn-outline btn-lg clipboard" data-clipboard data-clipboard-text="lg">
<span class="clipboard-idle"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4" aria-hidden="true"><rect width="14" height="14" x="8" y="8" rx="2"/><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/></svg>Copy</span>
<span class="clipboard-done"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4" aria-hidden="true"><path d="M20 6 9 17l-5-5"/></svg>Copied</span>
</button>
</div>
<div class="flex items-center gap-3">
<button type="button" class="btn btn-outline btn-xs btn-icon clipboard" data-clipboard data-clipboard-text="xs" aria-label="Copy">
<span class="clipboard-idle"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4" aria-hidden="true"><rect width="14" height="14" x="8" y="8" rx="2"/><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/></svg></span>
<span class="clipboard-done"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4" aria-hidden="true"><path d="M20 6 9 17l-5-5"/></svg></span>
</button>
<button type="button" class="btn btn-outline btn-sm btn-icon clipboard" data-clipboard data-clipboard-text="sm" aria-label="Copy">
<span class="clipboard-idle"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4" aria-hidden="true"><rect width="14" height="14" x="8" y="8" rx="2"/><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/></svg></span>
<span class="clipboard-done"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4" aria-hidden="true"><path d="M20 6 9 17l-5-5"/></svg></span>
</button>
<button type="button" class="btn btn-outline btn-icon clipboard" data-clipboard data-clipboard-text="default" aria-label="Copy">
<span class="clipboard-idle"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4" aria-hidden="true"><rect width="14" height="14" x="8" y="8" rx="2"/><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/></svg></span>
<span class="clipboard-done"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4" aria-hidden="true"><path d="M20 6 9 17l-5-5"/></svg></span>
</button>
<button type="button" class="btn btn-outline btn-lg btn-icon clipboard" data-clipboard data-clipboard-text="lg" aria-label="Copy">
<span class="clipboard-idle"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4" aria-hidden="true"><rect width="14" height="14" x="8" y="8" rx="2"/><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/></svg></span>
<span class="clipboard-done"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4" aria-hidden="true"><path d="M20 6 9 17l-5-5"/></svg></span>
</button>
</div>
Copy tag#
A .clipboard-tag is a monospace chip that copies the text it shows: an install command, an id, a coupon
code. The whole chip is the button. Put the text in a data-clipboard-content element and the two icons in a
.clipboard span; give the button an aria-label. Long text is cut short with an ellipsis, but
the whole of it is copied.
<div class="flex flex-wrap items-center justify-center gap-3">
<button type="button" class="clipboard-tag clipboard-tag-sm" data-clipboard aria-label="Copy bun add htmx-ui">
<code data-clipboard-content>bun add htmx-ui</code>
<span class="clipboard" aria-hidden="true"><span class="clipboard-idle"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4" aria-hidden="true"><rect width="14" height="14" x="8" y="8" rx="2"/><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/></svg></span><span class="clipboard-done"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4" aria-hidden="true"><path d="M20 6 9 17l-5-5"/></svg></span></span>
</button>
<button type="button" class="clipboard-tag" data-clipboard aria-label="Copy bun add htmx-ui">
<code data-clipboard-content>bun add htmx-ui</code>
<span class="clipboard" aria-hidden="true"><span class="clipboard-idle"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4" aria-hidden="true"><rect width="14" height="14" x="8" y="8" rx="2"/><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/></svg></span><span class="clipboard-done"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4" aria-hidden="true"><path d="M20 6 9 17l-5-5"/></svg></span></span>
</button>
<button type="button" class="clipboard-tag clipboard-tag-lg" data-clipboard aria-label="Copy bun add htmx-ui">
<code data-clipboard-content>bun add htmx-ui</code>
<span class="clipboard" aria-hidden="true"><span class="clipboard-idle"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4" aria-hidden="true"><rect width="14" height="14" x="8" y="8" rx="2"/><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/></svg></span><span class="clipboard-done"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4" aria-hidden="true"><path d="M20 6 9 17l-5-5"/></svg></span></span>
</button>
</div>
<div class="flex flex-wrap items-center justify-center gap-3">
<button type="button" class="clipboard-tag clipboard-tag-outline" data-clipboard aria-label="Copy WELCOME20">
<code data-clipboard-content>WELCOME20</code>
<span class="clipboard" aria-hidden="true"><span class="clipboard-idle"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4" aria-hidden="true"><rect width="14" height="14" x="8" y="8" rx="2"/><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/></svg></span><span class="clipboard-done"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4" aria-hidden="true"><path d="M20 6 9 17l-5-5"/></svg></span></span>
</button>
<button type="button" class="clipboard-tag clipboard-tag-sm clipboard-tag-outline" data-clipboard aria-label="Copy order id">
<code data-clipboard-content>ord_8f2a91c4e7d0</code>
<span class="clipboard" aria-hidden="true"><span class="clipboard-idle"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4" aria-hidden="true"><rect width="14" height="14" x="8" y="8" rx="2"/><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/></svg></span><span class="clipboard-done"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4" aria-hidden="true"><path d="M20 6 9 17l-5-5"/></svg></span></span>
</button>
<button type="button" class="clipboard-tag clipboard-tag-outline" data-clipboard data-clipboard-text="hx_secret_example_0c9e3f9a" aria-label="Copy secret key">
<code data-clipboard-content>hx_secret_••••3f9a</code>
<span class="clipboard" aria-hidden="true"><span class="clipboard-idle"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4" aria-hidden="true"><rect width="14" height="14" x="8" y="8" rx="2"/><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/></svg></span><span class="clipboard-done"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4" aria-hidden="true"><path d="M20 6 9 17l-5-5"/></svg></span></span>
</button>
</div>
The last one shows a shortened key but copies the whole of it: copy= in the macro, which writes
data-clipboard-text. .clipboard-tag-sm / .clipboard-tag-lg size it and
.clipboard-tag-outline gives it a border instead of a fill.
What it copies#
The first of these that is set:
| Attribute | Copies |
|---|---|
data-clipboard-text="…" | That text. |
data-clipboard-url="/page.md" | The text of that URL, fetched when clicked. The docs' "Copy Markdown" button works this way. |
data-clipboard-target="selector" | The nearest element matching the selector, looking outward from the button: its own block first, then further out, so #id works and so does a class shared by many blocks (.message-content, or pre:not([hidden]) code in code blocks). For an input, textarea or select, its value, read when clicked (so it copies what the user typed); for any other element, its text. |
data-clipboard-content | The text of that element inside the button (a copy tag). |
An input with a copy button: a read-only API key in an input group, and a share link the user can edit before copying.
<div class="field w-full max-w-sm">
<label class="label" for="clip-key">API key</label>
<div class="input-group">
<input class="input font-mono" id="clip-key" value="hx_live_7d2f9a41c0b8e6" readonly />
<span class="input-group-addon input-group-addon-inline-end">
<button type="button" class="btn btn-ghost btn-icon clipboard" data-clipboard data-clipboard-target="#clip-key" aria-label="Copy API key">
<span class="clipboard-idle"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4" aria-hidden="true"><rect width="14" height="14" x="8" y="8" rx="2"/><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/></svg></span>
<span class="clipboard-done"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4" aria-hidden="true"><path d="M20 6 9 17l-5-5"/></svg></span>
</button>
</span>
</div>
</div>
<div class="field w-full max-w-sm">
<label class="label" for="clip-link">Share link</label>
<div class="flex gap-2">
<input class="input" id="clip-link" value="https://example.com/invite/a8f3" />
<button type="button" class="btn btn-outline clipboard" data-clipboard data-clipboard-target="#clip-link">
<span class="clipboard-idle"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4" aria-hidden="true"><rect width="14" height="14" x="8" y="8" rx="2"/><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/></svg>Copy link</span>
<span class="clipboard-done"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4" aria-hidden="true"><path d="M20 6 9 17l-5-5"/></svg>Copied</span>
</button>
</div>
</div>
An element's text, such as an address:
12 Analytical Way
London NW1 6XE
<div class="flex w-full max-w-sm items-start justify-between gap-4 rounded-(--radius) border border-border p-4">
<address class="text-sm not-italic" id="clip-address">
Ada Lovelace<br />12 Analytical Way<br />London NW1 6XE
</address>
<button type="button" class="btn btn-ghost btn-sm btn-icon clipboard" data-clipboard data-clipboard-target="#clip-address" aria-label="Copy address">
<span class="clipboard-idle"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4" aria-hidden="true"><rect width="14" height="14" x="8" y="8" rx="2"/><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/></svg></span>
<span class="clipboard-done"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4" aria-hidden="true"><path d="M20 6 9 17l-5-5"/></svg></span>
</button>
</div>
Browsers and platforms#
- Secure pages (https, and localhost while developing) copy with the asynchronous Clipboard API, supported by every current browser on desktop, Android and iOS.
- Plain http, older browsers and iframes without the
clipboard-writepermission fall back todocument.execCommand("copy")on a hidden, read-only textarea. It is selected the way iOS Safari needs, doesn't open the phone keyboard or zoom the page, and focus goes back where it was. - If both fail (a browser that blocks clipboard access), the button gets
data-copy-failedfor the same two seconds, its icon turns red, "Copy failed" is announced andclipboard:errorfires. - Browsers only allow copying in response to the user, so call it from a click, not on page load. With
data-clipboard-url, the fetch is handed to the clipboard as a promise where the browser accepts one (Safari, Chrome), so the click still counts once the text arrives.
Events and htmx#
A copy fires a bubbling clipboard:copy with detail.text (or clipboard:error). Use
it as an htmx trigger to record the copy, or add a toast with
data-toast on the same button:
<button type="button" class="btn btn-outline clipboard" data-clipboard data-clipboard-text="https://example.com/r/8f2a" data-toast="Link copied" data-toast-type="success">
<span class="clipboard-idle"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4" aria-hidden="true"><rect width="14" height="14" x="8" y="8" rx="2"/><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/></svg>Copy referral link</span>
<span class="clipboard-done"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4" aria-hidden="true"><path d="M20 6 9 17l-5-5"/></svg>Copied</span>
</button>
<button type="button" class="btn btn-outline clipboard" data-clipboard data-clipboard-text="WELCOME20"
hx-post="/coupons/WELCOME20/copied" hx-trigger="clipboard:copy" hx-swap="none">…</button>
Copy buttons htmx swaps in work at once: the behaviour runs again on new content.
Nunjucks macros#
clipboard() writes a copy button, clipboard_tag() a copy tag.
{% from "components/clipboard/clipboard.html" import clipboard, clipboard_tag %}
{{ clipboard(text="npm i htmx-ui") }}
{{ clipboard(target="#api-key", icon_only=true, variant="ghost", size="sm", label="Copy API key") }}
{{ clipboard(text=url, label="Copy link", copied="Link copied", variant="secondary", timeout=3000) }}
{{ clipboard(text=code, icon=false, copied_icon=false) }}
{{ clipboard_tag("npm i htmx-ui") }}
{{ clipboard_tag("hx_secret_••••3f9a", copy=key, variant="outline", size="sm", label="Copy secret key") }}
Reference#
| Class / attribute | Description |
|---|---|
data-clipboard | Copy when clicked. On a button or a .clipboard-tag. |
.clipboard | Stacks .clipboard-idle and .clipboard-done in one space. On the button, or a span inside a tag. |
.clipboard-idle / .clipboard-done | The look before / after copying (shown while data-copied is set). |
.clipboard-tag | A monospace chip that copies its text. Sizes: .clipboard-tag-sm / -lg. .clipboard-tag-outline. |
data-clipboard-text | The text to copy. |
data-clipboard-target | A selector: copy the nearest match's value or text. |
data-clipboard-url | Copy the text of this URL, fetched when clicked. |
data-clipboard-content | Inside the button: copy this element's text. |
data-clipboard-timeout | How long data-copied stays, in ms (2000). |
data-clipboard-announce | What screen readers hear ("Copied"). |
data-copied / data-copy-failed | Set for the timeout after a copy / a failed copy. |
clipboard:copy / clipboard:error | Events with detail { text }. |