Categories:

Reading and copying selected text to clipboard using JavaScript

Updated: Nov 6th, 2015

Ask most developers how to copy the contents of a user selection to clipboard, and they'll mention the need for Flash (hence the popularity of scripts such as Zeroclipboard). However, an adjustment in that thinking is now due with recent improvements in browser support for the key piece of technology in JavaScript that makes copying to clipboard possible on its own- document.execCommand(). Supported in IE9+, Firefox 41+, and Chrome 42+, this JavaScript method finally brings native cut/copy support to browsers themselves. In this tutorial, we'll see how to read the textual contents of a user selection, dynamically select some text on the page, and last but not least, copy whatever is selected to clipboard, all using just JavaScript. We're entering a Flash free zone now!

Retrieving the text contents of the user selection

Lets start at the top, retrieving what the user has selected on the page as far as any textual contents. For this we use window.getSelection(), a method supported in all modern browsers and IE9+:

function getSelectionText(){
	var selectedText = ""
	if (window.getSelection){ // all modern browsers and IE9+
		selectedText = window.getSelection().toString()
	}
	return selectedText
}

window.getSelection() returns the currently selected text on the page and returns a Selection object containing that data. To retrieve the actual text, we use toString() to turn it into a string. The following example calls our function getSelectionText() whenever the user mouses up over the document so see what (if anything) the user has selected:

document.addEventListener('mouseup', function(){
	var thetext = getSelectionText()
	if (thetext.length > 0){ // check there's some text selected
		console.log(thetext) // logs whatever textual content the user has selected on the page
	}
}, false)

We check first that there's some text selected, as if the user simply clicked on the page, there will be none.

Selecting and reading the text contents of non form elements on the page

Moving on, instead of simply retrieving what the user has selected, we can also take charge and dynamically select then retrieve what we want on the page instead, such as the contents of a specific DIV. This is very different from simply using an element's innerHTML or innerText property to get its contents; we want to actually select that content via JavaScript, which opens up other possible operations such as copying it to the user's clipboard.

To select the textual contents of an non form field element, we start by creating a new Range object and setting it to encompass the desired element. Then, add the range to the Selection object to actually select it. Lets see exactly how this works with a function that dynamically selects an element's textual contents based on the element passed into it:

function selectElementText(el){
	var range = document.createRange() // create new range object
	range.selectNodeContents(el) // set range to encompass desired element text
	var selection = window.getSelection() // get Selection object from currently user selected text
	selection.removeAllRanges() // unselect any user selected text (if any)
	selection.addRange(range) // add range to Selection object to select it
}

To create a Selection object with which to add a range to, we use window.getSelection(); since this method by default returns the user selected text (if any), we call its removeAllRanges() method immediately afterwards to clear the slate. Then, we go about creating a blank range, zeroing in on the element's content to select using range.selectNodeContents(), before adding that range to the Selection object to select it.

Once we've selected the text we wish to read, we then turn to our previous getSelectionText() method to read the selected element's contents, for example:

Demo:

"My mama always said, 'Life was like a box of chocolates. You never know what you're gonna get.'" -Forrest

The code:

var para = document.getElementById('para')
selectElementText(para) // select the element's text we wish to read
var paratext = getSelectionText() // read the user selection
alert(paratext) // alerts "My mama always says..."

Selecting and reading the contents of form elements such as INPUT text or TEXTAREA

For selecting and reading form related field values such as INPUT text and TEXTAREA, the process differs from selecting regular text. Most of us already know to select the entire value of a form field, we could just use inputElement.select()*, and to retrieve that value, probe inputElement.value. However, there's also programmatically selecting a portion of the field's value and getting that value back. Lets see how to do that.

- Programmatically selecting a portion of a field's value

To dynamically select a portion of an INPUT text or TEXTAREA element, use formElement.setSelectionRange() to indicate the starting and ending index of the desired selection within the field:

var emailfield = document.getElementById("email")
emailfield.focus() // this is necessary in most browsers before setSelectionRange() will work
emailfield.setSelectionRange(0, 5) // select first 5 characters of input field
emailfield.setSelectionRange(5, emailfield.value.length) // select the 5th to last characters of input field

Note that the 2nd parameter of formElement.setSelectionRange() should be the index of the ending character to select plus 1, so to select the first 5 characters of a form field, the ending index value to enter should be 5, or 4 (the index of the 5th character) plus 1.

Demo:

 

*Note: In iOS devices (as of iOS9), using inputElement.select() to quickly select all of a form element's contents doesn't seem to work. However, using inputElement.setSelectionRange() does. So the following selects all of a form field's text across browsers and devices:

inputElement.setSelectionRange(0, inputElement.value.length)

- Reading the selected portion of a field's value

Regardless of how a portion of the form field's value is selected, whether by using setSelectionRange() to dynamically select that portion, or the user dragging his/her mouse to make a user defined selection, the way to retrieve the selection is to get the indices of the selection's starting and ending character, then extracting that portion from the form field's value using them. We can get the indices of the active selection using:

  • formElement.selectionStart: The index of the selected text's first character. If no text is selected, this contains the index of the character that follows the input cursor.
  • formElement.selectionEnd: The index of the selected text's last character. If no text is selected, this contains the index of the character that follows the input cursor.

The above properties are especially useful in getting any user selected text from a form field where the indices of the selection isn't already known. The following demo echoes what the user has selected from a TEXTAREA using these properties:

Demo (select some text inside textarea):

Output:

The code:

<textarea id="quote" cols="50" rows="5">
Some text here
</textarea>

<div id="output"></div>

<script>

var quotearea = document.getElementById('quote')
var output = document.getElementById('output')
quotearea.addEventListener('mouseup', function(){
	if (this.selectionStart != this.selectionEnd){ // check the user has selected some text inside field
		var selectedtext = this.value.substring(this.selectionStart, this.selectionEnd)
		output.innerHTML = selectedtext
	}
}, false)

</script>

We attach a "mouseup" event to the target TEXTAREA to listen for when the user mouses up inside it. Inside the event handler function, to detect what the user has selected, first, we check whether the TEXTAREA's selectionStart and selectionEnd properties contain different values- if they are the same, it means nothing has been selected, in which case they both point to the index of the character that follows the input cursor. If their values are different, we proceed with mapping the selected text's indices to the value of the form field value to derive the actual selected text, using formElement.value.substring().

Copying the selected text to user clipboard

Ok, now that the nitty gritty of how to read what was selected on the page is taken care of, whether on the page in general, or inside a specific DIV or form element, we can move on to the next pressing issue, actually copying that content to clipboard. As alluded to at the start of the tutorial, it comes down to using the method document.execCommand() to execute a command to "copy" (or "cut") the text to clipboard:

function copySelectionText(){
	var copysuccess // var to check whether execCommand successfully executed
	try{
		copysuccess = document.execCommand("copy") // run command to copy selected text to clipboard
	} catch(e){
		copysuccess = false
	}
	return copysuccess
}

The key here is the line document.execCommand("copy"), which actually performs the action to copy whatever is currently selected on the page to the clipboard. To detect whether the browser supports the execCommand() method properly, we put the operation inside a try/catch() block; if the call to execCommand() fails, we know the browser doesn't support this method.

We can use our newly conjured copySelectionText() function with any of the previous methods for selecting/ retrieving some text to then copy it to clipboard. For example, the snippet below would copy whatever the user has selected on the page when the user mouses up over the document:

document.body.addEventListener('mouseup', function(){
	var copysuccess = copySelectionText() // copy user selected text to clipboard
}, false)

We can refine this process though to only perform a "copy" action if the user selection actually contains some data; if the user simply clicks on the page without highlighting anything for example, no data is selected, in which case the copy action should be aborted. This can be done simply by looking at what was selected by the user beforehand:

document.body.addEventListener('mouseup', function(){
	var selected = getSelectionText() // call getSelectionText() to see what was selected
	if (selected.length > 0){ // if selected text length is greater than 0
		var copysuccess = copySelectionText() // copy user selected text to clipboard
	}
}, false)

Time for a live demo now. Try selecting any text inside the following paragraph to see its contents copied to clipboard (press "Ctrl V" afterwards to paste and confirm). I've also added a tooltip that shows up temporarily to indicate success each time:

Demo (select any text inside the paragraph below to copy it to clipboard):

"To enjoy good health, to bring true happiness to one's family, to bring peace to all, one must first discipline and control one's own mind. If a man can control his mind he can find the way to Enlightenment, and all wisdom and virtue will naturally come to him." -Buddha

The code:

createtooltip() // create tooltip by calling it ONCE per page. See "Note" below
var buddhaquote = document.getElementById('buddhaquote')
buddhaquote.addEventListener('mouseup', function(e){
	var selected = getSelectionText() // call getSelectionText() to see what was selected
	if (selected.length > 0){ // if selected text length is greater than 0
		var copysuccess = copySelectionText() // copy user selected text to clipboard
		showtooltip(e)
	}
}, false)

Note: Click here for the source to the tooltip function.

Copying the selected form field value to user clipboard

Moving on, we can easily perform the same hat trick on form field values. In the next example we add a control next to an INPUT text field to let users quickly copy its value:

Demo:

Share this tutorial Copy

The code:

<script>

function copyfieldvalue(e, id){
	var field = document.getElementById(id)
	field.focus()
	field.setSelectionRange(0, field.value.length)
	var copysuccess = copySelectionText()
	if (copysuccess){
		showtooltip(e)
	}
}

</script>

<fieldset style="max-width:600px">
	<legend>Share this tutorial</legend>
	<input id="url" type="text" size="60" value="http://www.javascriptkit.com/javatutors/copytoclipboard.shtml" /> 
	<a href="#" onClick="copyfieldvalue(event, 'url');return false">Copy</a>
</fieldset>

Copying a DIV's contents to clipboard

And finally, just for good measure, lets also see an example of auto selecting and copying a DIV's contents to clipboard upon clicking on it:

Demos (click on any of the quotes below to select its contents):

"Just when the caterpillar thought the world was ending, he turned into a butterfly." --Proverb
"Great minds discuss ideas; average minds discuss events; small minds discuss people." --Eleanor Roosevelt
"No one can make you feel inferior without your consent." --Eleanor Roosevelt

The code:

<div id="motivatebox" style="overflow: hidden; margin: 1em auto">
	<div class="motivate">
	"Just when the caterpillar thought the world was ending, he turned into a butterfly." --Proverb
	</div>

	<div class="motivate">
	"Great minds discuss ideas; average minds discuss events; small minds discuss people." --Eleanor Roosevelt
	</div>
	
	<div class="motivate">
	"No one can make you feel inferior without your consent." --Eleanor Roosevelt
	</div>
</div>

<script>

var motivatebox = document.getElementById('motivatebox')

motivatebox.addEventListener('mouseup', function(e){
	var e = e || event // equalize event object between modern and older IE browsers
	var target = e.target || e.srcElement // get target element mouse is over
	if (target.className == 'motivate'){
		selectElementText(target) // select the element's text we wish to read
		var copysuccess = copySelectionText()
		if (copysuccess){
			showtooltip(e)
		}
	}
}, false)

</script>

Nothing new here- we simply monitor the "mouseup" event of the quotes DIVs' shared parent container to detect when the user has clicked on one of those inner DIVs. When that happens, we select the DIV"s contents before copying it to clipboard using the functions created earlier.

In Conclusion

As you can see, reading, and more importantly, copying text to the clipboard can now be a fully JavaScript affair. With Flash falling out of favour fast with browsers and users alike, this is good news indeed. All of the examples above work in IE9+, Firefox 41+, and Chrome 42+.

End of Tutorial