Copy & Paste & The Web

Avatar of Chris Coyier
Chris Coyier on (Updated on )

Have you ever tried to copy and paste some text only to find it frustrating, awkward, or even impossible? I bet you have. It’s not random. On the web, you have a decent amount of control over it. Let’s just lay a bunch of stuff out there as food for thought.

Not Actually Text

Perhaps this is the most obvious problem, so let’s not dwell on it. If text can be “real text” on the web, please do that. Compared to an image of text, real text is more accessible, more indexable, and more useful. You can select it to copy and paste!

Accidental Overlaps

Have you ever seen that effect where text fades out at the bottom? It’s often done by laying a gradient image over top of that text. You can see through part of it, but that element is still sitting on top of the text, meaning mouse interaction happens on the overlap, not the text.

Because of the overlap, I can’t properly select the text I want here. Worse, the link at the bottom is unclickable.

In this demo, the overlap is a pseudo element filled with a a gradient and positioned on top. Thankfully, this is largely a fixable situation. pointer-events: none; on the overlap will go a long way in helping. With that set, pointer interactions will totally ignore the element. Clicks will go right through as if it wasn’t even there.

That’s great, except IE 10 doesn’t support pointer-events. If you still wanted to rely on that, Modernizr v3 has a test for it, so you could only apply the overlay if you knew pointer-events worked.

Or, instead of an overlay at all, you could color individual lines to make it look like a fadeout as we covered in this article.

The Post-Selection Popup

Some sites make some pretty big assumptions after you’ve selected some text. A common one is: OH GOOD YES HELLO HI I SEE YOU OBVIOUSLY MUST WANT TO SHARE THIS BIT OF TEXT ON SOCIAL MEDIA LET ME HELP. Not everyone is a fan. Aside from being presumptuous and over-eager, it can get in the way of screenshotting.

Highlighter.js is a library that makes this all-too-easy.

CSS Control Over Selectability

There is actually a CSS property specifically for controlling the selectability of text: user-select.

.unselectable {
  -webkit-user-select: none;  /* Chrome all / Safari all */
  -moz-user-select: none;     /* Firefox all */
  -ms-user-select: none;      /* IE 10+ */
  user-select: none;          /* Likely future */       
}

Aside from a few browser quirks, text with that set is unselectable. That can be pretty useful when trying to design better UX around the selectability of text on your site.

On mobile, text selection in generally done by a long tap which brings up some text selection choices. You can prevent that “callout” (and thus prevent the selection of text), with:

-webkit-touch-callout: default   /* displays the callout */
-webkit-touch-callout: none      /* disables the callout */

Other visible text that doesn’t copy

You can force text to be unselectable with the CSS above, but some text isn’t selectable automatically:

Accidentally Selecting Line Numbers

Once in a while you’ll run across a chunk of code on a website you want to copy and paste. After you paste it, you find the line numbers came along with it.

It’s kind of surprising actually, since it seems like you’d have to go out of you way to make that happen. Knowing what we know now, those line numbers could have used CSS to prevent them from being copied. Or the code could have been marked up as a list to show the numbers that won’t copy. Or it could have used custom counters which wouldn’t copy. Or pseudo elements before the lines that wouldn’t copy (relevant article).

So the only way this can happen is if they just plopped some text right in the element at the start of the line and did nothing to prevent it from being copied. Likely a pretty easy fix we could encourage any offender to do.

Selecting (All) Text with JavaScript

Form elements are often used for this. If you want to provide some text that is specifically for copy-and-pasting, you typically put it in an input or textarea.

<textarea id="ta">a bunch of text</textarea>

Then it’s really easy to select that text programmatically:

var ta = document.getElementById("ta");
ta.focus();
ta.select();

You can’t really do that on a

or whatever. Also, if a user is inside a form element, the typical “Select All” command will only select the text within the bounds of that element, which is nice, expected behavior.

If you want the behavior where the text gets selected as you click into it, here’s a pretty succinct jQuery way to do it:

$('#ta').on("focus", function(e) {
  e.target.select();
  $(e.target).one('mouseup', function(e) {
    e.preventDefault();
  });
});

That bit with the mouseup allows the text to remain selected after the mouseup event. Normally the mouseup will deselect the text and activate the cursor.

I like this way because it also doesn’t force all the text to be selected no matter what (which people don’t like), just on the inital focus. So after the focus, if you want to change the selection yourself and only copy a part of the text, you can do that.

Google Fonts is an offender here. If you just want a part of the text, too bad, you get it all.

If you don’t provide click-to-select, that sometimes makes people unhappy too, so it’s a balance. Hence why I like the focus-to-select, then let it be approach above.

There is a lot more to know about selecting text with JavaScript, including Range selection and stuff, which is pretty complicated and best saved for another article.

Copying to the Clipboard Programmatically

This ability just recently surfaced in JavaScript. At the time of this writing, just Chrome and IE. It’s done through document.execCommand('copy');

There is a whole history here that I’m not quite up-to-snuff with. I think it was largely a security concern that was why it was impossible in JavaScript. Not to mention a tastefulness concern (who wants to visit a site only to find their clipboard messed with?). For whatever reason, it’s available again.

Matt Gaunt offers some example code:

Email me at [email protected]

var copyEmailBtn = document.querySelector('.js-emailcopybtn');  
copyEmailBtn.addEventListener('click', function(event) {  
  // Select the email link anchor text  
  var emailLink = document.querySelector('.js-emaillink');  
  var range = document.createRange();  
  range.selectNode(emailLink);  
  window.getSelection().addRange(range);  
    
  try {  
    // Now that we've selected the anchor text, execute the copy command  
    var successful = document.execCommand('copy');  
    var msg = successful ? 'successful' : 'unsuccessful';  
    console.log('Copy email command was ' + msg);  
  } catch(err) {  
    console.log('Oops, unable to copy');  
  }  
    
  // Remove the selections - NOTE: Should use   
  // removeRange(range) when it is supported  
  window.getSelection().removeAllRanges();  
});

Copying text to the clipboard programmatically has always been a desire though. We used to have to use flash, typically a library called ZeroClipboard. Here’s a David Walsh tutorial on that.

How To Paste With/Without Style/Formatting

When you copy text, it generally comes along with formatting.

On Macs, there is a Paste and Match Style command though, which can be very useful to get rid of that formatting when you don’t want it. Like when pasting into an email. Command-Shift-V is the usual shortcut for that.

Side note: notice the right-clicking I’m doing here to copy. Some users do that. Disabling right-clicking (as you can do in JavaScript) is an inhibition to those users worth avoiding.

I generally prefer this behavior, so I did the thing where I mapped it to Command-V (overriding normal paste).

You can still paste which formatting through the menus if you need to.

Extra Crap on the Clipboard

Have you ever selected some text from a site, only to find when you paste it that it has happened some extra crap to the end of your selection? READ MORE AT FART-KNUCKLE.BUSINESS!!!

Don’t do that.

Awkward Retained Capitalization

You can capitalize text in CSS with text-transform: uppercase;. It causes a rather large (annoying) functionality difference in copy-pasting though across browsers.

From what I tested quickly:

  • Firefox and IE respect the original text (what is in the DOM).
  • Chrome, Safari, Opera, and iOS respect the CSS capitalization.

I prefer the former.

Block Links Can Make It Harder To Copy

In HTML5, we learned we can now wrap anchor tags around whatever we want. Even though they are inline elements, we can wrap them around blocks without worry of being invalid. It doesn’t come without repercussion though.

Title

This makes the entire block title a link without any CSS assistance, but it does make the title a bit harder to copy. Wrapping that markup around and doing h3 &gt; a { display: block; } makes it a little easier, assuming there is a bit of padding on the h3, because then you can start the selection in the padding and move.

So on one hand there is a larger click area, and on another it’s slightly harder to copy (if you’re a normal right-to-left copier). Your call.

See the Pen Block titles kinda hard to copy by Chris Coyier (@chriscoyier) on CodePen.

Sometimes block structure itself can cause annoying situations. Like here, you’re trying to select a movie title, but a pixel too far and you get a bunch of weird text in totally unrelated positions:

It’s not that huge of an issue here as I think people are a bit used to this and know how to back off and get what they need. But it’s worth considering. Even things like flexbox ordering can totally change how text selection behaves even when visually things look identical.

See the Pen flex ordering and selection by Chris Coyier (@chriscoyier) on CodePen.

Pasting into the Console

Classic rube mistake: Copying the “$ ” at the beginning of console commands in blog posts about how to do terminal things. HANDS UP people. Just me? Dammit. Anyway. There is a pretty funny dotfile thing to warn you when you do it.

Any more?

Have any pet peeves about copy and paste, or selection in general, on the web?