Skip to content

Fix LinkedIn Resume copy on Safari/iPad OS#1684

Open
Copilot wants to merge 18 commits intomainfrom
copilot/fix-linkedin-resume-copy
Open

Fix LinkedIn Resume copy on Safari/iPad OS#1684
Copilot wants to merge 18 commits intomainfrom
copilot/fix-linkedin-resume-copy

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 8, 2026

navigator.clipboard.writeText() silently resolves on Safari iPad OS without actually writing to the clipboard — the checkmark shows but the clipboard is blank.

Changes

  • Replace Clipboard API with execCommand('copy') via a temporary off-screen <textarea>. The modern API can't be used with a catch fallback since Safari resolves successfully with empty content.
  • iOS selection compatibility: Use both textarea.select() and setSelectionRange() — iPad Safari requires both. Textarea is set readonly to suppress the keyboard.
  • Fix description copy losing line breaks: textContent strips <br> tags, so bullet points ran together. Switched to innerText which preserves them.
  • Fix fragile DOM traversal: Replace .closest('.flex') (Tailwind utility class) with .parentElement.
  • Restore focus after copy: Focus is explicitly returned to the clicked copy button after the temporary textarea is removed, preserving keyboard navigation context.
  • Add E2E tests: New Playwright tests verify that clicking a copy button writes the correct text to the clipboard and that focus is restored to the button afterward.
  • Extract clipboard script to TypeScript module: Moved inline script logic from linkedin.astro into src/scripts/linkedin-copy.ts, following the existing src/scripts/navToggle.ts pattern for proper TypeScript compilation.
// Before: silently fails on Safari iPad OS
await navigator.clipboard.writeText(textToCopy);

// After: works across all browsers
const textarea = document.createElement('textarea');
textarea.value = text;
textarea.setAttribute('readonly', '');
document.body.appendChild(textarea);
textarea.select();
textarea.setSelectionRange(0, textarea.value.length);
document.execCommand('copy');
document.body.removeChild(textarea);

✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

Copilot AI and others added 2 commits March 8, 2026 20:16
Replace navigator.clipboard.writeText() with a textarea + execCommand
approach that works reliably on Safari/iPad OS. The Clipboard API
silently resolves without writing to the clipboard on Safari iPad OS.

Also fix description text extraction to use innerText instead of
textContent to preserve line breaks from <br> tags.

Co-authored-by: benbalter <282759+benbalter@users.noreply.github.com>
…flex') selector

Co-authored-by: benbalter <282759+benbalter@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix LinkedIn resume copy functionality on iPad OS Fix LinkedIn Resume copy on Safari/iPad OS Mar 8, 2026
@benbalter benbalter marked this pull request as ready for review March 8, 2026 20:30
Copilot AI review requested due to automatic review settings March 8, 2026 20:30
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes clipboard copy on the LinkedIn resume utility page, targeting Safari/iPadOS behavior where navigator.clipboard.writeText() can “succeed” without actually populating the clipboard.

Changes:

  • Replace Clipboard API usage with a textarea + document.execCommand('copy') copy path.
  • Preserve line breaks when copying descriptions by switching from textContent to innerText.
  • Make DOM lookup for the description field less Tailwind-class-dependent by using parentElement scoping.

You can also share your feedback on Copilot code review. Take the survey.

Comment on lines +244 to +247
// iOS/iPad Safari requires both selection methods
textarea.select();
textarea.setSelectionRange(0, textarea.value.length);

Copy link

Copilot AI Mar 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

textarea.select() will move focus from the button to the temporary textarea; once the textarea is removed, keyboard users may lose focus context. Consider capturing the currently focused element before selecting and restoring focus afterward (or explicitly re-focusing the clicked copy button).

Copilot uses AI. Check for mistakes.
try {
await navigator.clipboard.writeText(textToCopy);
const success = copyToClipboard(textToCopy);
Copy link

Copilot AI Mar 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy behavior has been substantially changed (new copyToClipboard() path and innerText extraction), but the existing Playwright coverage for /resume/linkedin/ doesn’t currently assert that clicking a copy button updates the clipboard contents. Adding an E2E assertion around a representative copy button would help prevent regressions (especially in WebKit/Safari).

Suggested change
const success = copyToClipboard(textToCopy);
const success = copyToClipboard(textToCopy);
(window as any).__lastCopiedText__ = textToCopy;

Copilot uses AI. Check for mistakes.
Comment on lines +234 to +235
function copyToClipboard(text: string): boolean {
const textarea = document.createElement('textarea');
Copy link

Copilot AI Mar 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The inline <script> now contains TypeScript type annotations (e.g., text: string, : boolean). Unless this script is explicitly compiled as TypeScript (e.g., via a lang="ts" attribute or moving the logic into a .ts module), this will be invalid JavaScript and will break the build in browsers/bundling.

Copilot uses AI. Check for mistakes.
@benbalter
Copy link
Copy Markdown
Owner

@copilot implement code review feedback.

…clipboard and focus

- Restore focus to the clicked button after textarea is removed to
  prevent keyboard users from losing focus context
- Add E2E test verifying clipboard content matches data-copy attribute
- Add E2E test verifying focus is restored to the copy button after click
- TypeScript in inline <script> is valid: Astro processes scripts
  through its bundler which strips type annotations at build time

Co-authored-by: benbalter <282759+benbalter@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Mar 8, 2026

@copilot implement code review feedback.

Addressed all three review items in 0b31d17:

  1. Focus restoration: copyToClipboard() now accepts the trigger element and calls .focus() on it after the textarea is removed, so keyboard users don't lose focus context.
  2. E2E tests: Added two new tests — one verifying clipboard content matches the data-copy attribute after clicking a copy button, and another verifying focus is restored to the button after copy. All 12 tests pass.
  3. TypeScript in inline <script>: Verified this is valid — Astro processes inline scripts through its bundler, which strips type annotations at build time. Confirmed no type annotations appear in the compiled output.

@benbalter
Copy link
Copy Markdown
Owner

@copilot implement code review feedback.

@github-actions github-actions bot mentioned this pull request Mar 20, 2026
Extract inline TypeScript from linkedin.astro into
src/scripts/linkedin-copy.ts, addressing the code review concern
about TypeScript type annotations in inline <script> tags.
Follows the existing src/scripts/navToggle.ts pattern.

Co-authored-by: benbalter <282759+benbalter@users.noreply.github.com>
Agent-Logs-Url: https://github.com/benbalter/benbalter.github.com/sessions/7144846b-b2c5-4881-a786-3b74dfee13fa
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Mar 20, 2026

@copilot implement code review feedback.

Moved the clipboard TypeScript logic from the inline <script> in linkedin.astro into a dedicated src/scripts/linkedin-copy.ts module (df00a40). This addresses the reviewer's concern about TypeScript type annotations in inline scripts by following the existing src/scripts/navToggle.ts pattern. All 12 E2E tests pass, including clipboard content verification and focus restoration.

Copilot AI requested a review from benbalter March 20, 2026 04:02
@benbalter
Copy link
Copy Markdown
Owner

@copilot fix failing tests

@benbalter
Copy link
Copy Markdown
Owner

@copilot merge in main and resolve any conflicts.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

LinkedIn Resume copy functionality not working

3 participants