Liking cljdoc? Tell your friends :D

x-copy

A copy-to-clipboard button component. Resolves the text to copy from multiple sources in priority order, writes it to the clipboard via the Clipboard API, and shows a brief tooltip confirming success or failure. Supports plain-text and HTML copy modes, keyboard hotkeys, and fully customizable messaging.


Tag

<x-copy text="Hello, world!">Copy</x-copy>

Attributes

AttributeTypeDefaultDescription
textstringText to copy directly. Evaluated at copy time, not registration time.
fromstringCSS selector identifying a source element. At copy time the element is queried from the document root.
from-attrstringWhen from is set: name of an attribute on the target element to copy. If absent, the element's textContent is used.
modeenum: "text" | "html""text"Copy mode. "html" writes an HTML + plain-text ClipboardItem; falls back to plain-text copy if ClipboardItem is unavailable.
disabledboolean presenceabsent = enabledDisables the button and suppresses copy on hotkey.
show-tooltipboolean (default-true)trueWhether to show the success/error tooltip. Absent = true; "false" = disabled.
tooltip-msnumber (100–10000)1200How long the tooltip stays visible in milliseconds.
success-messagestring"Copied"Tooltip text on successful copy.
error-messagestring"Copy failed"Tooltip text when the copy operation fails.
hotkeystringGlobal keyboard shortcut that triggers copy(). Format: modifier keys joined by + followed by the key, e.g. "ctrl+c", "meta+shift+c". Case-insensitive.

Properties

PropertyTypeReflects attribute
textstringtext
fromstringfrom
fromAttrstringfrom-attr
modestringmode
disabledbooleandisabled
showTooltipbooleanshow-tooltip
tooltipMsnumbertooltip-ms
successMessagestringsuccess-message
errorMessagestringerror-message
hotkeystringhotkey
textValuestring— (property-only)

textValue is a property-only override. When set, it takes precedence over all attribute-based text resolution. Setting it to null or undefined restores normal resolution.


Events

EventBubblesComposedCancelableDetail
x-copy-requestyesyesyes{ text: string, mode: string, from: string \| null, fromAttr: string \| null }
x-copy-successyesyesno{ text: string }
x-copy-erroryesyesno{ error: unknown }

x-copy-request fires before the clipboard write with the fully resolved text. Calling preventDefault() aborts the copy — no clipboard write and no x-copy-success or x-copy-error fires.


Text Resolution Priority

At copy time the component resolves the text to copy in this order:

  1. textValue property (if non-empty string).
  2. text attribute (if present and non-empty).
  3. from attribute → query the document for the selector → if from-attr is also set, read that attribute from the element; otherwise use the element's textContent.
  4. Empty string "".

Methods

MethodSignatureDescription
copy() => Promise<string>Programmatically triggers a copy. Resolves with the copied text on success, rejects on failure. Fires the full event sequence.

Slots

SlotDescription
(default)Content rendered inside the trigger button. Typically a label string or an icon.
tooltipOverride the tooltip content entirely. When this slot is populated the success-message and error-message attributes are ignored for rendering (events still fire).

Parts

PartDescription
wrapOutermost <div> wrapping button and tooltip.
triggerThe <button> element.
tooltipTooltip container <div>. Hidden until a copy attempt completes.
tooltip-text<span> inside the tooltip that holds the message text.

Tooltip Behavior

When a copy attempt completes (success or error), if show-tooltip is not false:

  • [data-tooltip-open] is added to the host element.
  • [data-tooltip-kind] is set to "success" or "error" on the host element.
  • After tooltip-ms milliseconds, both attributes are removed and the tooltip hides.

These host attributes can be used in external CSS for custom tooltip styling:

x-copy[data-tooltip-open][data-tooltip-kind="error"] {
  /* custom error state */
}

HTML Copy Mode

When mode="html":

  1. The ClipboardItem API is attempted with both text/html and text/plain blobs (the resolved text is used for both, or the HTML source for text/html).
  2. If ClipboardItem is not available (older browsers, non-HTTPS), the component falls back to a plain-text clipboard write using navigator.clipboard.writeText.

CSS Custom Properties

VariableDefaultDescription
--x-copy-tooltip-bg#1a1a1a (light) / #f0f0f0 (dark)Tooltip background color.
--x-copy-tooltip-fg#f0f0f0 (light) / #1a1a1a (dark)Tooltip text color.
--x-copy-tooltip-radius4pxTooltip border-radius.
--x-copy-tooltip-offset6pxGap between trigger and tooltip.

Accessibility

  • The trigger is a native <button> — keyboard accessible by default.
  • aria-label should be set on the component or the button slot content should be descriptive.
  • When disabled, the button receives the HTML disabled attribute; it is skipped by tab order.
  • The tooltip is announced via role="status" and aria-live="polite" so screen readers read the confirmation message without moving focus.
  • The tooltip element is aria-hidden="true" when not visible to prevent spurious announcements.

Keyboard

KeyConditionAction
Enter / SpaceTrigger focused, not disabledTriggers copy().
hotkey valueDocument keydown, not disabledTriggers copy().

Examples

HTML

<!-- Copy a literal string -->
<x-copy text="Hello, world!">Copy greeting</x-copy>

<!-- Copy from another element's textContent -->
<code id="snippet">npm install @example/lib</code>
<x-copy from="#snippet">Copy</x-copy>

<!-- Copy an attribute value -->
<a id="link" href="https://example.com">Example</a>
<x-copy from="#link" from-attr="href">Copy link</x-copy>

<!-- HTML mode -->
<div id="rich"><strong>Bold text</strong> and plain text</div>
<x-copy from="#rich" mode="html">Copy rich text</x-copy>

<!-- Disabled -->
<x-copy text="unavailable" disabled>Copy</x-copy>

<!-- No tooltip -->
<x-copy text="silent" show-tooltip="false">Copy silently</x-copy>

<!-- Custom messages -->
<x-copy text="custom" success-message="Done!" error-message="Oops!">Copy</x-copy>

<!-- Global hotkey -->
<x-copy text="shortcut value" hotkey="meta+shift+c">Copy (⌘⇧C)</x-copy>

<!-- Handle events -->
<x-copy id="monitored" text="watched">Copy</x-copy>
<script>
  const el = document.getElementById('monitored');
  el.addEventListener('x-copy-request', e => {
    if (!confirm('Allow copy?')) e.preventDefault();
  });
  el.addEventListener('x-copy-success', e => console.log('Copied:', e.detail.text));
  el.addEventListener('x-copy-error',   e => console.error('Failed:', e.detail.error));
</script>

ClojureScript (hiccup)

;; Copy literal text
[:x-copy {:text "Hello, world!"} "Copy greeting"]

;; Copy from element
[:x-copy {:from "#snippet"} "Copy"]

;; Copy attribute value
[:x-copy {:from "#link" :from-attr "href"} "Copy link"]

;; HTML mode
[:x-copy {:from "#rich" :mode "html"} "Copy rich text"]

;; Disabled
[:x-copy {:text "unavailable" :disabled true} "Copy"]

;; Custom duration and messages
[:x-copy {:text "hi" :tooltip-ms "2000"
          :success-message "Copied!" :error-message "Oops!"} "Copy"]

;; Listen to events
[:x-copy
  {:text "watched"
   :on-x-copy-request #(when-not (js/confirm "Allow?") (.preventDefault %))
   :on-x-copy-success #(js/console.log "Copied:" (.. % -detail -text))
   :on-x-copy-error   #(js/console.error "Error:"  (.. % -detail -error))}
  "Copy"]

Can you improve this documentation?Edit on GitHub

cljdoc builds & hosts documentation for Clojure/Script libraries

Keyboard shortcuts
Ctrl+kJump to recent docs
Move to previous article
Move to next article
Ctrl+/Jump to the search field
× close