{"record":{"id":"d1b3c6b0be2d43db","repo":"greensock/GSAP","slug":"copy-didn-t-work-this-browser-doesn-t-permit-that","errorCode":null,"errorMessage":"Copy didn't work; this browser doesn't permit that.","messagePattern":"Copy didn't work; this browser doesn't permit that\\.","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"src/MotionPathHelper.js","lineNumber":65,"sourceCode":"\t\t_copyElement.style.display = \"none\";\n\t\t_body.appendChild(_copyElement);\n\t},\n\t_parsePath = (path, target, vars) => (_isString(path) && _selectorExp.test(path)) ? _doc.querySelector(path) : Array.isArray(path) ? _rawPathToString(_arrayToRawPath([{x:gsap.getProperty(target, \"x\"), y:gsap.getProperty(target, \"y\")}, ...path], vars)) : (_isString(path) || path && (path.tagName + \"\").toLowerCase() === \"path\") ? path : 0,\n\t_addCopyToClipboard = (target, getter, onComplete) => {\n\t\ttarget.addEventListener('click', e => {\n\t\t\tif (e.target._gsHelper) {\n\t\t\t\tlet c = getter(e.target);\n\t\t\t\t_copyElement.value = c;\n\t\t\t\tif (c && _copyElement.select) {\n\t\t\t\t\tconsole.log(c);\n\t\t\t\t\t_copyElement.style.display = \"block\";\n\t\t\t\t\t_copyElement.select();\n\t\t\t\t\ttry {\n\t\t\t\t\t\t_doc.execCommand('copy');\n\t\t\t\t\t\t_copyElement.blur();\n\t\t\t\t\t\tonComplete && onComplete(target);\n\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\tconsole.warn(\"Copy didn't work; this browser doesn't permit that.\");\n\t\t\t\t\t}\n\t\t\t\t\t_copyElement.style.display = \"none\";\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t},\n\t_identityMatrixObject = {matrix:{a:1, b:0, c:0, d:1, e:0, f:0}},\n\t_getConsolidatedMatrix = target => (target.transform.baseVal.consolidate() || _identityMatrixObject).matrix,\n\t_findMotionPathTween = target => {\n\t\tlet tweens = gsap.getTweensOf(target),\n\t\t\ti = 0;\n\t\tfor (; i < tweens.length; i++) {\n\t\t\tif (tweens[i].vars.motionPath) {\n\t\t\t\treturn tweens[i];\n\t\t\t} else if (tweens[i].timeline) {\n\t\t\t\ttweens.push(...tweens[i].timeline.getChildren());\n\t\t\t}\n\t\t}","sourceCodeStart":47,"sourceCodeEnd":83,"githubUrl":"https://github.com/greensock/GSAP/blob/13e2b790546426a1a2e0e9b409f3f8dc6d6611f2/src/MotionPathHelper.js#L47-L83","documentation":"MotionPathHelper's copy-to-clipboard helper relies on the deprecated document.execCommand('copy'). When the browser refuses (or execCommand throws), it warns that copying is not permitted. The helper catches the exception internally and continues, hiding the copy element afterward.","triggerScenarios":"Calling the MotionPathHelper copy feature in a browser/context where execCommand('copy') is blocked: no user gesture, iframe without allow, insecure (http) context where clipboard API is restricted, or very old/strict browsers.","commonSituations":"Clicking the helper's copy button inside a sandboxed iframe or headless test environment; using it in an automated test where no user activation exists; HTTPS-only clipboard policies.","solutions":["Trigger the copy from a real user gesture (click handler)","Use the modern Clipboard API manually: navigator.clipboard.writeText(text)","Serve the page over HTTPS/localhost so clipboard permissions are granted","Polyfill/select the text and instruct the user to press Ctrl+C as a fallback"],"exampleFix":"// before\n// relying on MotionPathHelper's internal execCommand copy\n// after\nconst text = target.getAttribute('d');\nif (navigator.clipboard) {\n  await navigator.clipboard.writeText(text);\n} else {\n  console.warn('Clipboard unavailable; copy manually:', text);\n}","handlingStrategy":"fallback","validationCode":"function canCopy() {\n  return !!(navigator.clipboard && navigator.clipboard.writeText) || (document.queryCommandSupported && document.queryCommandSupported('copy'));\n}","typeGuard":null,"tryCatchPattern":"try {\n  await navigator.clipboard.writeText(text);\n} catch (err) {\n  // fallback: select text for manual copy\n  const ta = document.createElement('textarea');\n  ta.value = text;\n  document.body.appendChild(ta);\n  ta.select();\n  try { document.execCommand('copy'); } catch (e) { prompt('Copy manually:', text); }\n  ta.remove();\n}","preventionTips":["Prefer navigator.clipboard.writeText over execCommand","Only copy inside user-gesture handlers","Serve over HTTPS/localhost","Provide a manual-copy fallback in iframes"],"tags":["clipboard","browser-compatibility","execcommand"],"backgroundTag":"clipboard-permission-denied","analyzedSha":"13e2b790546426a1a2e0e9b409f3f8dc6d6611f2","analyzedAt":"2026-08-29T08:34:05.027Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}