Copy to Clipboard

Free

Copy button in inline, block and icon-only variants with success feedback, the async Clipboard API and an execCommand fallback for older browsers.

</>sv-copy-to-clipboard clipboardcopyutility
import { SvCopyToClipboardComponent } from '@styloviz/layout';

Demo & usage

Basic usage

Usage example — open the gallery for the full interactive demo.

An interactive demo for this component lives in the gallery.

Open live demo

More examples

Icon-only button

example.htmlAngular
<sv-copy-to-clipboard [text]="apiKey" variant="icon-only" size="sm" successLabel="Copied!" (copyError)="onCopyError($event)" />

A secret: masked, gated reveal, audited copy

The label is masked, revealing asks the host first, the success announcement warns, and every copy emits an SvSensitiveCopyEvent that never carries the value.

example.htmlAngular
<sv-copy-to-clipboard variant="block"
  [text]="apiKey" [label]="apiKey"
  [sensitive]="true" sensitiveReveal="revealable" sensitiveField="apiKey"
  [revealAuthorized]="stepUpDone()"
  (revealRequest)="stepUp()"
  (copyAudited)="audit.log($event)" />

Why did it fail?

copyError emits an SvClipboardError whose reason is denied, insecure-context, unavailable or failed.

example.htmlAngular
onCopyError(err: unknown) {
  if (err instanceof SvClipboardError && err.reason === 'insecure-context') {
    this.toast.show('Copying needs HTTPS — select the text and press Ctrl+C.');
  }
}

Drive it from a test (or a native shell)

example.htmlAngular
providers: [{ provide: SV_CLIPBOARD, useValue: { writeText: () => Promise.reject(new SvClipboardError('denied')) } }]

When to use

  • Letting users copy a value (code snippet, API key, URL, token) in one click.
  • You want built-in success feedback and a clipboard fallback for old browsers.
  • For copying rich/multiple values, build a custom control around the clipboard API.

Async states

None — this component has nothing to load, so it has no loading, empty or error state to drive.

Inputs

NameTypeDefaultDescription
textstring''Text to copy to clipboard.
successLabelstring'Copied!'Label shown after successful copy.
successDurationnumber2000Duration in ms before reverting to default state.
variantCopyVariant'inline'Display variant.
sizeCopySize'md'Component size.
labelstring''Placeholder shown when no text content is provided via ng-content.
ariaLabelstring'Copy to clipboard'Accessible name of the copy button — the only name `icon-only` has. Name WHAT is copied ("Copy API key"), and localise it here. Never derived from `label`, which may be the (sensitive) value itself.
sensitivebooleanfalseTreat the value as a secret — an API key, a recovery code, a token. A COPIED SECRET LEAVES NO TRACE AND GETS NO WARNING from a generic copy button. On: the `label` is masked, the success announcement becomes `sensitiveWarning`, and every copy emits `copyAudited`. Off by default — the common use is a command or an id, and masking those would break them.
sensitiveRevealCopySensitiveReveal'masked'How a `sensitive` label is shown: `masked`, `revealable` (toggle) or `visible`.
sensitiveFieldstring'value'Which field was copied, for the audit event's `field`.
sensitiveWarningstring'Copied. This value is secret — do not …Announced (and shown in the block variant) after a sensitive copy.
requireAuthorizationbooleantrueWhether revealing a `sensitiveReveal="revealable"` value needs the host's authorization first. While on and `revealAuthorized` is off, the toggle emits `revealRequest` instead of revealing — step up, then set `revealAuthorized`.
revealAuthorizedbooleanfalseThe host has re-authenticated the user; the reveal toggle may reveal.
copyTimeoutnumberSV_COPY_TIMEOUT_MSHow long (ms) a clipboard write may stay pending before it is abandoned as `failed` and `busy` clears. A write that never settles — a permission prompt left open, a native bridge that never answers — would otherwise leave the button busy forever. A late answer after the timeout is ignored. An invalid value (`0`, negative, `NaN`, `Infinity`) uses the default.

Outputs

EventPayload typeDescription
copiedvoidEmitted after text is successfully copied.
copyErrorunknownEmitted when copying fails (both the Clipboard API and the fallback), or when the write did not settle within `copyTimeout`. The payload is an `SvClipboardError`: `reason` classifies it — `denied`, `insecure-context`, `unavailable` or `failed` (also used for a timeout). When both paths ran and failed, `cause` (and so `message`) is the FALLBACK's error — the last one thrown — while `reason` is derived from the Clipboard API's rejection. Typed `unknown` for compatibility; narrow with `instanceof SvClipboardError`.
copyAuditedSvSensitiveCopyEventA `sensitive` value reached the clipboard. The event says who, which field and when — never the value itself. Log it.
revealRequestvoidThe user asked to reveal while `requireAuthorization` was on and `revealAuthorized` off.

Customization & theming

  • Pass the `text` to copy and choose a `variant` (inline, block, icon-only) and `size`.
  • Customize the `label` and the post-copy `successLabel` / `successDuration`.
  • Listen to `copied` for success and `copyError` for failures, to trigger toasts or analytics.
  • Sensitive values (`sensitive`, `sensitiveReveal`, `sensitiveField`, `sensitiveWarning`, `requireAuthorization` / `revealAuthorized` / `revealRequest`, `copyAudited`) follow the kit-wide sensitive-value policy, and `provideSvSensitivePrivacy()` re-masks the label while the screen is shared.
  • The clipboard sits behind the `SV_CLIPBOARD` injection token (default `svBrowserClipboard`): provide your own to test denied permission or an insecure origin, or to target a native shell.
  • Variant axes: `variant` and `size` are appearance; `sensitive` + `sensitiveReveal` are a behavioural mode that works with every variant, except that `icon-only` has no label to mask or reveal, so it only warns and audits.
  • Busy state: a click while a copy is in flight is ignored and the button reports `aria-busy="true"`; the success timer is cleared when the component is destroyed, and a copy that settles after destruction emits nothing. A write that never settles is abandoned after `copyTimeout` (default 10 000 ms, `SV_COPY_TIMEOUT_MS`): `copyError` fires with reason `failed`, busy clears, and a late answer is ignored.
  • Layout (X-9): not applicable — the button and label sit in normal flow; nothing is portalled, measured or scrolled, and no containing block or breakpoint matters. The execCommand fallback appends an off-screen `position: fixed` textarea to `<body>` for the duration of the copy only, and removes it whether the copy succeeded or not.
  • Browser limits: the async Clipboard API needs a secure context (HTTPS or localhost) and a user gesture, and an iframe needs the `clipboard-write` permission policy. Elsewhere the component falls back to the deprecated `execCommand('copy')`, which iOS Safari only honours inside the tap handler and which browsers may remove. When both fail, `copyError` carries `reason` (`denied`, `insecure-context`, `unavailable`, `failed`) and the live region tells the user to select the text and copy it manually.

Best practices

  • Do: Confirm the copy visibly (`successLabel`) so users know it worked.
  • Do: Give icon-only variants an accessible name with `ariaLabel` that says what is copied ("Copy API key") — `label` is visible text, and may be the value itself.
  • Tip: Use the `copied` event to fire a toast or analytics event.
  • Do: Set `sensitive` for API keys, recovery codes and tokens: the label masks, the copy warns, and `copyAudited` gives you an audit trail that never contains the secret.
  • Don't: Don't project a secret through `<ng-content>` in sensitive mode — projected markup is yours and is not masked. Pass it through `label`.

Accessibility

  • Renders a labelled button with an accessible name even in icon-only mode.
  • Success and failure are announced via a polite live region, not colour-only; a failure names its reason and the manual workaround.
  • Falls back to execCommand when the Clipboard API is unavailable, and emits `copyError` if both fail.
  • In sensitive mode the reveal toggle is a real button with `aria-pressed`, and the success announcement is the `sensitiveWarning`.
  • Focus stays on the copy button: the fallback's scratch textarea hands focus back after it copies.

Feedback on Copy to Clipboard

Spotted a gap in this page, or something that didn't work as described? Comments are GitHub Discussions in the public styloviz/community repo, so posting needs a GitHub account.

Loads giscus.app and GitHub — nothing is fetched until you click.