When One WebKit Bug Quietly Breaks Copy in Every App
A WebKit bug leaves the Copy menu item always enabled, even with nothing selected — and it rides the shared engine into Safari, Mail, and third-party RSS readers. Here's the lesson for builders.
A WebKit bug that leaves the Copy menu item always enabled — even when nothing is selected on the page — sounds like the smallest possible problem. But it's a good window into something every builder hits eventually: when you depend on a shared engine, you inherit its bugs in every app you ship.
Jeff Johnson wrote it up at lapcatsoftware.com (original article) after John Gruber of Daring Fireball asked him to reproduce it. I want to talk less about the bug itself and more about why a one-line behaviour shows up in apps that never wrote that line.
🔍 What the bug actually does
In a normal Mac app, Edit → Copy is greyed out when you have nothing selected. That greying-out is a signal: the system is telling you the command would do nothing, so it won't let you trigger it. It's a small, decades-old courtesy of the platform.
WebKit breaks that signal. When a web page (or an email message rendered by WebKit) has focus, Copy stays enabled regardless of selection. Hit it with nothing highlighted and:
- Nothing gets copied.
- Nothing pastes afterward.
- But the clipboard is not technically empty — WebKit has touched it.
Key takeaway: The damage isn't "Copy does nothing." It's that an always-on menu item lies to you about whether an action is meaningful, and quietly writes to shared clipboard state when you expected it to stay out.
That last point matters more than it looks. Plenty of workflows assume the clipboard only changes when you changed it. An engine that nudges clipboard state on a no-op copy is the kind of thing that bites you three layers downstream.
🌐 Why it spreads to apps that never caused it
Here's the part worth sitting with. On Apple platforms, WebKit is a public API. It isn't locked to Safari. Any third-party app can embed a WKWebView to render HTML, and a lot of them do.
So a single defect in the shared engine surfaces everywhere the engine is used:
| App | Maker | Renders content with | Shows the bug? |
|---|---|---|---|
| Safari | Apple | WebKit | Yes |
| Apple | WebKit (message view) | Yes | |
| NetNewsWire | Open source | WebKit (article view) | Yes |
| Vienna | Open source | WebKit (article view) | Yes |
NetNewsWire and Vienna are RSS readers — Gruber uses one, Johnson the other — and neither team wrote the buggy menu logic. They inherited it the moment they chose the platform's web view instead of building a renderer from scratch. Which, to be clear, is the right call. Nobody should reimplement a browser engine to show RSS articles.
This is the shared-dependency tax. You get a battle-tested HTML renderer for almost free, and in exchange you also ship its bugs under your own app's name.
💡 The lesson for anyone building on a platform you don't control
If you're a student or a small-team builder in Sri Lanka shipping on free and open-source stacks, this pattern is your daily reality. You lean on Next.js, on a browser engine, on a UI library, on someone's npm package. You move fast precisely because you didn't write that code.
The trade is the same one NetNewsWire made. A few things I take from it:
- A bug in a dependency becomes your bug to your users. They file it against your app, not against WebKit. Triage starts with "is this us or upstream?"
- You usually can't fix the root cause — you can only report it and add a workaround in your own layer.
- Test the boundaries, not just the happy path. The empty-selection Copy is exactly the edge case nobody clicks during a demo.
- Don't trust that "nothing happened" means nothing changed. Side effects on shared state (clipboard, focus, global config) are where these bugs hide.
If you're building a small web utility yourself, the practical version is: validate your own UI state instead of assuming the framework did it for you. We keep a set of free, no-signup developer tools for exactly this kind of quick check while building — and even those are only as correct as the libraries under them.
🛠️ What a workaround looks like (and why it's annoying)
You can't patch WebKit. So if this bug genuinely hurt your app, you'd be stuck doing UI-state work the engine was supposed to do for you:
- Intercept the Copy menu action in your own app code.
- Ask the web view whether a selection actually exists before letting Copy proceed.
- Re-enable or disable the menu item yourself based on that answer.
Bottom line: Working around an upstream bug means re-doing the platform's job in your own codebase — more code to maintain, for a problem you didn't create. That's why a "tiny" shared-engine bug is worth more attention than its size suggests.
It's also why reports like Johnson's are valuable. One careful write-up, reproduced across four apps, turns "is it just me?" into a documented, fixable defect with a clear blast radius.
What this means for you
The Copy menu staying enabled is harmless on its own. The structure behind it is not. Every dependency you pick is a quiet promise that its bugs become yours, in your users' eyes, under your app's name.
For builders on a learning budget, that's not a reason to avoid shared libraries — they're the only way a small team ships anything serious. It's a reason to:
- Know what's under you, and where its edges are.
- Write down and report the weird behaviour when you hit it, the way Johnson did.
- Keep your own validation layer thin but present, so an upstream slip doesn't silently corrupt state you care about.
Use the platform. Just don't assume the platform always told you the truth about what it did.
Original source
WebKit Always Enables the Copy Menu Item in Every App