Copy Button
shadcn-htmx/copy-buttonFreeComponent
A native <button> that writes an associated string (snippet, API key, URL) to the clipboard with the Async Clipboard API, then flips to a transient aria-live "Copied" state. Progressive-enhancement fallback for non-secure contexts. Ships in five flavours: Hono JSX (TypeScript), Jinja2 macro, Go html/template, Phoenix function component, and a raw HTML snippet. Follows the WAI-ARIA APG button pattern.
Live preview
live · rendered by the registry
Rendered by shadcn-htmx on their own page — this is the component running, not a screenshot of it.Install it
npx shadcn@latest add https://shadcn-htmx.productdevbook.com/r/copy-button.jsonSource
1/** @jsxImportSource hono/jsx */2import { cn, type ClassValue } from "@/registry/lib/cn"34// Copy Button — shadcn-htmx, htmx v4 + Tailwind v4.5//6// Click-to-copy button: writes an associated string (a snippet, an API key, a7// URL) to the system clipboard, then flips to a transient "Copied" state and8// announces it through a visually-hidden aria-live region. The docs site's own9// code-block is a consumer.10//11// Built on the Async Clipboard API. navigator.clipboard.writeText(text)12// returns a Promise that resolves once the system clipboard has been updated;13// it works only in a secure context (HTTPS / localhost) and from a window that14// has focus:15// repos/mdn/files/en-us/web/api/clipboard/writetext/index.md16// The shared behaviour in site.js follows web.dev's progressive-enhancement17// recipe — use the async API when present, otherwise fall back to a throwaway18// <textarea> + document.execCommand('copy'):19// repos/web.dev/src/site/content/en/patterns/clipboard/copy-text/index.md20//21// Accessibility:22// - A native <button> gives us role=button + Space/Enter activation for free23// (APG button pattern: repos/aria-practices/content/patterns/button/).24// - The transition is announced through an EMPTY element carrying25// aria-live="polite": site.js writes "Copied" into it on success. MDN: the26// aria-live attribute is set on an empty element that is then populated, so27// AT announces the change without moving focus —28// repos/mdn/files/en-us/web/accessibility/aria/reference/attributes/aria-live/index.md29// - This is NOT a toggle: aria-pressed is wrong here (the label/state is30// transient feedback, not a sticky on/off), so we use aria-live instead.31//32// All hx-*, data-* and aria-* attributes are forwarded onto the <button> via33// {...rest}, so the button can also trigger an htmx request if you want one.3435export type CopyButtonVariant = "outline" | "ghost" | "secondary"36export type CopyButtonSize = "default" | "sm" | "icon"3738const base =39 "inline-flex shrink-0 items-center justify-center gap-1.5 rounded-md text-sm font-medium whitespace-nowrap transition-all outline-none " +40 "focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 " +41 "disabled:pointer-events-none disabled:opacity-50 " +42 "[&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-3.5 " +43 // Transient success state. site.js sets data-copied="true" for a beat, then44// … truncated
More from shadcn-htmx
All 83 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Accordionaccordion | shadcn-htmx | Components | Free | no deps | |
| Active Searchactive-search | shadcn-htmx | Components | Free | no deps | |
| Alertalert | shadcn-htmx | Components | Free | no deps | |
| Alert Dialogalert-dialog | shadcn-htmx | Components | Free | no deps | |
| Aspect Ratioaspect-ratio | shadcn-htmx | Components | Free | no deps | |
| Auto Gridauto-grid | shadcn-htmx | Components | Free | no deps | |
| Autocompleteautocomplete | shadcn-htmx | Components | Free | no deps | |
| Autosize Textareaautosize-textarea | shadcn-htmx | Components | Free | no deps |
