clipboard copy falls back correctly inside dialogs

This commit is contained in:
Jarek Krochmalski committed 2026-09-06 17:03:48 +05:30
1 parent 2640641262
commit 1e7f680426
1 file changed
+15 -3
+15 -3
View File
@@ -12,20 +12,32 @@ export async function copyToClipboard(text: string): Promise<boolean> {
}
}
// Fallback: hidden textarea + execCommand for HTTP contexts
// Fallback: hidden textarea + execCommand for HTTP (insecure) contexts, where
// navigator.clipboard is unavailable. The textarea must live INSIDE the current
// focus-trap (e.g. a shadcn/bits-ui Dialog): appended to document.body it sits
// outside the trap, which yanks focus back to the dialog before execCommand runs,
// so the copy silently fails and pastes stale clipboard content (#1488). Mount it
// in the open dialog when there is one, else document.body.
try {
const openDialog = document.querySelector<HTMLElement>('[role="dialog"]');
const host = openDialog ?? document.body;
const active = document.activeElement as HTMLElement | null;
const textarea = document.createElement('textarea');
textarea.value = text;
textarea.setAttribute('readonly', '');
textarea.style.position = 'fixed';
textarea.style.left = '-9999px';
textarea.style.top = '-9999px';
textarea.style.opacity = '0';
document.body.appendChild(textarea);
host.appendChild(textarea);
textarea.focus();
textarea.select();
textarea.setSelectionRange(0, textarea.value.length);
const ok = document.execCommand('copy');
document.body.removeChild(textarea);
host.removeChild(textarea);
// Restore focus to whatever the user had (keeps the dialog's focus-trap happy).
active?.focus?.();
if (ok) return true;
} catch {
/* fall through */