Skip to content

Copy to clipboard

A read-only value that exists to be copied — a share URL, an API token, a generated SQL / config snippet — should not force a manual select-all + Ctrl/Cmd-C (especially poor on touch). The installCopy behavior wires a plain <button> to copy a named element’s value, signals success, and fires an event you can chain — all from declarative markup, so it works under a strict Content-Security-Policy: default-src 'self' (no inline JS).

The previews on this page are already live — copy is purely client-side (installCopy reads the named element and writes to the clipboard), so there is no server contract and no api/recipes/copy/ namespace. The other recipes’ live demos talk to this site’s demo API; this one needs nothing beyond the markup below.

Point data-hc-copy at the element to copy with a CSS selector. The behavior copies a form control’s value (input / textarea / select) or any other element’s textContent.

To copy a fixed string instead of a referenced element, use data-hc-copy-text:

AttributeRequiredNotes
data-hc-copyone sourceCSS selector of the element to copy (value or textContent).
data-hc-copy-textone sourceA literal string to copy (used instead of data-hc-copy).
data-hc-copy-ok(optional)Success text announced to assistive tech. Defaults to copy.ok (“Copied”) from the i18n catalog.

On a successful copy the behavior:

  • sets data-hc-copied on the button for ~1.5 s — style the transient affordance however you like (the button’s own accessible name is never changed):

    .hc-button[data-hc-copied] { /* e.g. show a check, tint the button */ }
  • announces the success label through a behavior-owned, visually-hidden role="status" live region;

  • dispatches a bubbling hc:copied event with detail: { text }.

hc:copied is a normal bubbling event — copy never opens a toast itself. To raise one on copy with no inline JS, listen for the event and dispatch hc:toast:

document.addEventListener('hc:copied', () => {
document.body.dispatchEvent(new CustomEvent('hc:toast', {
bubbles: true,
detail: { message: 'Copied to clipboard', variant: 'success' },
}));
});
  • The trigger is a real <button> — keyboard-activatable and touch-friendly (click, not hover).
  • Success is announced via a role="status" region; the button keeps its own accessible name throughout (it is never relabeled to “Copied”).

The Clipboard API needs a secure context (https / localhost). Where it is unavailable the click is a graceful no-op; for a form-control target the behavior best-effort selects its text so the user can copy manually. The underlying value is always visible and selectable without the behavior.

  • Toast — pair with hc:copied to confirm the copy.
  • i18n — translate the copy.ok success label.