3

Before someone suggests it: no, user-select isn't the correct answer.

Daniel O'Connor's pure CSS method is close but I can't use it for my use case because of those "Accessibility concerns".

I need a better way of doing the same thing. I can't think of how it'd be done; I don't think there's a reliable cross-browser compatible way of copying something to the clipboard with JavaScript. So I think it has to be a HTML & CSS solution.

Edit

I say "I don't think there's a reliable cross-browser compatible way of copying something to the clipboard with JavaScript" because one solution could've been to catch when the copy event (if that's even supported everywhere). I just realised though even if "there's a reliable cross-browser compatible way of copying something to the clipboard with JavaScript", this probably wouldn't work when a user copies the text on a mobile device. Correct me if I'm wrong.

Edit 2

I'm not trying to block people from copying the text in any way. I'm not trying to block access to the text. That's impossible and discouraged anyway. I'm just trying to make it nicer for users who are copying N number of elements' text from my app who end up with unimportant stuff in the clipboard (like timestamp elements' text, etc.)

Community
  • 1
  • 1
Adam Lynch
  • 3,341
  • 5
  • 36
  • 66
  • @MoshMage Ctrl+C is only one method for copying text. My question is concerned with copying in general; including using a mobile device's native controls for copying. – Adam Lynch Apr 09 '15 at 11:29
  • What are your accessibility concerns? – Type-Style Apr 09 '15 at 11:30
  • 1
    What you're trying to achieve is not possible at all. Accept it, life goes on. – Marco Bonelli Apr 09 '15 at 11:33
  • @AdamLynch I don't see why you should **deny under any circumnstances** the right of the user to copy the content. Just the fact that the page is downloaded by the user's browser means that the whole content has been already "stolen" from you, and you cannot control it anymore. – Marco Bonelli Apr 09 '15 at 11:38
  • @MarcoBonelli pfft read my latest edit. – Adam Lynch Apr 09 '15 at 11:40
  • @AdamLynch oh I see, perhaps you should reformulate adding an example... it wasn't really clear what you were trying to achieve. – Marco Bonelli Apr 09 '15 at 11:59
  • @AdamLynch The accepted answer in the link doesn't deal with CTRL+C - it disabled the actual selection of the element by returning false ---- but after reading the second edit I've noticed that it isn't what you want – MoshMage Apr 09 '15 at 13:09
  • 1
    Yeah @MoshMage but whether or not it's a duplicate surrounds the question not the answers or comments. Ok cool. – Adam Lynch Apr 09 '15 at 13:40
  • @MoshMage Can we remove the duplicate flag on the question? – Adam Lynch Apr 09 '15 at 15:09
  • @AdamLynch sure, I deleted the post but am not quite sure how to remove the flag – MoshMage Apr 10 '15 at 08:35

2 Answers2

4

New Answer

You want to automatically omit certain parts of the text when users select and copy it.

I know two solutions for this:

  1. Put the text in different parent elements
  2. Hide the unwanted elements when the user starts selecting

Solution #1 is usually used for source code with line numbers. By clever applying CSS, two DIV's are aligned vertically so that each line number appears to be on the left of the correct line of source code (which is actually in a different DIV).

That way, you can drag your selection in the source code without getting any of the line numbers. This works well for information that can be displayed in boxes that are vertically/horizontally aligned or, to use a different picture, if you could put things into different table cells.

Solution #2 responds to the first mouse click and applies display: none to elements with a certain class like omit-during-copy.

The advantage of this approach is that the user can see what they are copying (i.e. the unwanted information is vanishing).

The disadvantage is how/when to revert the state.

A variant of this is to use absolute positioning to make elements appear in a certain place. This becomes tedious very quickly if your have to apply the technique to things like aHIDEb - you will have to put enough empty space between a and b to display HIDE between them, then place HIDE pixel perfect in the gap. Not impossible but I'd try to rearrange the information first.

Old Answer

There are two ways to prevent a user from copying text from your HTML page:

  1. Don't display it
  2. Use a password field

Let me explain: There is a small amount of things that you can try with JavaScript in the page itself. If you swallow Ctrl+C, then people will use the mouse. If you swallow the mouse button in the page, they will use the menu bar. If you disable the menu bar of the browser, people will deactivate the option "Allow JavaScript to hide the menu bar".

If you use a password field, people will use the JavaScript console or the "Show Source" or they'll use tools like Tampermonkey to get rid of your pesky intrusion into their lives.

You can try to display an image with the text instead. People will then use OCR. So even if you used a Flash-based HTML viewer to replace the whole page, people could still copy the text. But it would make them pretty mad.

Personal note: I tend to visit pages which try things like that once and briefly at that. I tend to remember such sites for a long time and with very negative emotions. So if I were you, I try this only to drive people away from my site.

Aaron Digulla
  • 321,842
  • 108
  • 597
  • 820
  • Sorry, I don't think this is what I need. I've added a second edit to the question to clarify. – Adam Lynch Apr 09 '15 at 11:41
  • Basically, you want to remove some info from the page when the user presses Ctrl+C. See my edits. – Aaron Digulla Apr 09 '15 at 12:02
  • 1
    Better title for the quesion: "Prevent some elements from being copied into the clipboard" and in the question "I would like to make it more comfortable for people to copy some information from my page. The information contains unwanted parts like time stamps, line numbers and the like." – Aaron Digulla Apr 09 '15 at 12:05
  • Thanks for your updated answer. Interesting. #1 breaks accessibility again though because the source order is wrong :/. #2 is more interesting. I need to make sure this works on mobile too but let's say that's possible. A better way might be to somehow replace the text with non-selectable text (i.e. Daniel O'Connor's method) when the user starts selecting. – Adam Lynch Apr 09 '15 at 13:45
  • #2 should work with any kind of browser; it's a simple "hide element" method that already worked 10 years ago. If you use O'Connor's method, it doesn't make sense to add/replace the attribute when the user starts selecting since that doesn't add anything - the marked elements already are unselectable. – Aaron Digulla Apr 09 '15 at 13:49
  • I meant detecting when stuff is selected on mobile, not `display:none`, but should be fine. Hiding an element mightn't make sense depending on the element, it's a visual change like. What I'm saying is that there might be a way to achieve this by converting `

    hello

    ` to `

    ` when the user starts selecting. As far as the user can tell, nothing has changed.
    – Adam Lynch Apr 09 '15 at 14:21
  • I'm not I get what you mean when you say "that doesn't add anything - the marked elements already are unselectable" – Adam Lynch Apr 09 '15 at 14:22
  • I'd prefer to see what the selection contains while I drag. Otherwise, people will be confused why something is missing in the clipboard despite seeing it as "selected" on the screen. As for the `data` attribute: It shouldn't make a difference if you use it from the start or if you add it on demand; the on demand case just adds overhead without any advantages. – Aaron Digulla Apr 09 '15 at 14:26
  • In my case at least, the text can't be selected anyway. – Adam Lynch Apr 09 '15 at 15:07
  • To put it another way: The `data` attributes violates the [principle of least astonishment](http://en.wikipedia.org/wiki/Principle_of_least_astonishment) since the text might appear selected on screen in some browsers but it won't make it to the clipboard and users will wonder why that is. – Aaron Digulla Apr 09 '15 at 15:22
  • Ah ok @Aaron, you're saying it's possibly a surprise because user-select mightn't be supported. Ok. – Adam Lynch Apr 09 '15 at 17:07
4

In case someone is still looking for a way to prevent copying unimportant elements (such as line numbers), the answer is to use pseudo elements:

.code {
  white-space: pre;
  font-family: monospace;
  padding-left: 40px;
}
.line-number {
  position: absolute;
  left: 0;
  width: 38px;
  color: #888;
  text-align: right;
}
.line-number::before {
  content: attr(data-line-number);
}
<div class="code">
<span class="line-number" data-line-number="1"></span>const greet = () => {
<span class="line-number" data-line-number="2"></span>  console.log("Hello World!");
<span class="line-number" data-line-number="3"></span>};
</div>
riv
  • 6,846
  • 2
  • 34
  • 63