zenorocha/clipboard.js · error · Error

Invalid "target" attribute. Please use "readonly" instead of

Error message

Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute

What it means

Thrown when `action` is 'copy' and the target DOM element carries a `disabled` attribute. Disabled form controls are not selectable and have no selectable value, so the library refuses to copy from them and tells you to use `readonly` instead, which keeps the field selectable while still non-editable.

Source

Thrown at src/actions/default.js:22

/**
 * Inner function which performs selection from either `text` or `target`
 * properties and then executes copy or cut operations.
 * @param {Object} options
 */
const ClipboardActionDefault = (options = {}) => {
  // Defines base properties passed from constructor.
  const { action = 'copy', container, target, text } = options;

  // Sets the `action` to be performed which can be either 'copy' or 'cut'.
  if (action !== 'copy' && action !== 'cut') {
    throw new Error('Invalid "action" value, use either "copy" or "cut"');
  }

  // Sets the `target` property using an element that will be have its content copied.
  if (target !== undefined) {
    if (target && typeof target === 'object' && target.nodeType === 1) {
      if (action === 'copy' && target.hasAttribute('disabled')) {
        throw new Error(
          'Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute'
        );
      }

      if (
        action === 'cut' &&
        (target.hasAttribute('readonly') || target.hasAttribute('disabled'))
      ) {
        throw new Error(
          'Invalid "target" attribute. You can\'t cut text from elements with "readonly" or "disabled" attributes'
        );
      }
    } else {
      throw new Error('Invalid "target" value, use a valid Element');
    }
  }

  // Define selection strategy based on `text` property.

View on GitHub (pinned to 899378dee9)

Solutions

  1. Replace the `disabled` attribute on the target with `readonly` — readonly fields remain selectable and copyable while preventing edits.
  2. If the field must stay disabled for form-submission reasons, copy via the `text` callback instead of the `target` selector: `new ClipboardJS(btn, { text: () => field.value })`.
  3. Dynamically swap `disabled` for `readonly` (or remove it) in the trigger's click handler before the clipboard action runs.
  4. If disabled state is essential, render a separate non-disabled mirror element (e.g., a read-only span) and point the target at it.

Example fix

// before
<input id="token" value="abc123" disabled />
<button class="btn" data-clipboard-target="#token">Copy</button>
// after
<input id="token" value="abc123" readonly />
<button class="btn" data-clipboard-target="#token">Copy</button>
Defensive patterns

Strategy: validation

Validate before calling

function canCopyFrom(el) {
  if (!el || el.nodeType !== 1) return false;
  if (el.hasAttribute('disabled')) return false;
  return true;
}
const el = document.querySelector('#token');
if (!canCopyFrom(el)) {
  // use text callback or swap to readonly before copying
  new ClipboardJS(btn, { text: () => el.value });
} else {
  new ClipboardJS(btn, { target: () => el });
}

Type guard

/**
 * @param {Element} el
 * @returns {boolean}
 */
function isCopyableElement(el) {
  return el instanceof Element && el.nodeType === 1 && !el.hasAttribute('disabled');
}

Try / catch

try {
  ClipboardActionDefault({ action: 'copy', target: el });
} catch (err) {
  if (/use "readonly" instead of "disabled"/.test(err.message)) {
    // fall back to reading the value directly via the text path
    ClipboardActionCopy(el.value, { container });
  } else {
    throw err;
  }
}

Prevention

When it happens

Trigger: Copying from an `<input>`/`<textarea>` that is `<input disabled ...>` with `new ClipboardJS(el, { text: () => field.value })` won't hit this, but using a `target` selector pointing at `document.querySelector('input[disabled]')` with the default copy action will; binding `data-clipboard-target="#myDisabled"` on a trigger where `#myDisabled` is a disabled input; copying directly via `ClipboardActionDefault({ action: 'copy', target: disabledEl })`.

Common situations: Form fields that toggle between disabled and readonly states (e.g., a disabled submit-time input the user wants to copy); copy buttons on grayed-out fields in admin UIs; migrating from native `disabled` styling to clipboard copy without changing the attribute; ARIA-correct disabled controls that also set the HTML disabled attribute.

Related errors


AI-assisted analysis of zenorocha/clipboard.js@899378dee9 (2026-08-13). Data as JSON: /api/errors/ead2864c0884163a. Report an issue: GitHub.