Skip to content

fix: fall back to execCommand when clipboard API is unavailable#598

Draft
sudocarlos wants to merge 1 commit into
tale:mainfrom
sudocarlos:fix/clipboard-insecure-context
Draft

fix: fall back to execCommand when clipboard API is unavailable#598
sudocarlos wants to merge 1 commit into
tale:mainfrom
sudocarlos:fix/clipboard-insecure-context

Conversation

@sudocarlos

Copy link
Copy Markdown

What

Clicking any copy-to-clipboard action (code block, copyable attribute value, or the IP address menu on the Machines page) threw an uncaught TypeError: Cannot read properties of undefined (reading 'writeText') in the browser console and silently failed to copy anything.

Why

navigator.clipboard only exists in secure contexts (HTTPS or localhost). Headplane is frequently self-hosted and accessed over plain HTTP (LAN, reverse proxy without TLS to the browser, etc.), so navigator.clipboard is undefined there, and calling .writeText(...) on it threw instead of failing gracefully or falling back to a legacy copy method.

Fix

  • Added copyToClipboard(text) in app/utils/clipboard.ts: tries navigator.clipboard.writeText when available, and falls back to the legacy document.execCommand("copy") approach (via a temporary off-screen <textarea>) when the Clipboard API is unavailable or the write fails. Returns true/false instead of throwing.
  • Updated the three call sites (code-block.tsx, attribute.tsx, machine-row.tsx) to use the new helper and toast a "Failed to copy ..." message on failure instead of crashing.

Testing

  • pnpm run typecheck and pnpm run lint pass.
  • Manually verified copy still works via the fallback path when navigator.clipboard is unset.

closes #597

navigator.clipboard only exists in secure contexts (HTTPS or
localhost), which self-hosted Headplane is often not served over.
Calling writeText on it threw an uncaught TypeError and silently
failed to copy, in the code block, copyable attribute, and machine
IP address menu.

Add a copyToClipboard helper that falls back to the legacy
document.execCommand("copy") approach and reports success/failure
so callers can toast accordingly.

closes tale#597
@github-actions github-actions Bot added the UI/UX Related to the frontend UI label Jul 22, 2026
@sudocarlos

Copy link
Copy Markdown
Author

Code Review

Reviewed the diff directly (the automated code-reviewer subagent had no shell/browser access in this session, so I did this pass manually).

Summary

Clean, targeted fix. copyToClipboard() correctly guards the Clipboard API behind a feature check + try/catch and falls back to execCommand("copy"), returning a boolean instead of throwing. All three call sites were updated consistently.

Blockers

None.

Warnings

None.

Suggestions (non-blocking)

  • app/components/attribute.tsx:48-54 — the early return on copy failure now runs before the SVG check/copy icon toggle, which is actually an improvement (icon no longer flips to "copied" on failure). Just flagging this behavior change explicitly since it wasn't called out in the PR description — worth confirming it's intentional (it reads as correct to me).
  • app/utils/clipboard.tsdocument.execCommand is deprecated, but this is the standard/expected fallback pattern for insecure contexts and it's scoped correctly with try/catch/finally. No changes needed.
  • Nice touch keeping the JSDoc comment style consistent with app/utils/time.ts.

Import ordering, toast("Failed to ...") phrasing, and lint/typecheck all pass and match existing conventions. LGTM.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

UI/UX Related to the frontend UI

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Copy-to-clipboard crashes on insecure (HTTP) contexts

1 participant