Detecting Select All on the Web

Sam Thorogood - Jun 4 '19 - - Dev Community

On the web, hitting Cmd/Ctrl-A (or triggering "Select All" another way) has two distinct modes of operation.

If your focus is inside a <textarea>, <input>, or any element marked with contentEditable—that is, typing keys would enter text there—then Select All will select all of that element's contents. Great! But otherwise...

Problem

🚨 If a user is focused in a non-editable part of your page, they'll instead select all of the page's content.

Select-All in the Twitter interface

And for a user on a site which predominantly features a large editor (like a blog authoring interface!), this might be frustrating. The content of a <textarea> will look 👀 selected... because in a way, it is, as a byproduct of the whole page being selected, but:

  • typing (or pasting) won't replace the content
  • copy will copy the entire page, including the text of UI elements

Solution

Let's detect when the user triggers Select All, and redirect their selection to an editor of your choice. This solution is already in place on Emojityper. 😂⌨️

If you've read my other posts, you might remember that I'm not a huge fan of hooking into keyboard events directly—there's many ways to trigger Select All, and not all of them are tapping Ctrl/Cmd-A.

So the solution has three steps:

  1. adding two hidden, but selectable elements to your page
  2. listening for the selectionchange event
  3. calling .focus() on your editor.

1. Hidden Elements

Add two hidden elements to your page, which are selectable, but invisible (not display: none—they need to be on the page), with CSS like:



.extent {
  position: fixed;
  opacity: 0;
  user-select: auto;  /* to always allow select-all */
}
.extent::after {
  content: '\200b';   /* zero-width space */
}


Enter fullscreen mode Exit fullscreen mode

We then add these at the top and bottom of your page (this could also be done programatically in JS):



<body>
<div class="extent"></div>

<!-- your regular page here -->
<p><a href="https://dev.to/samthor">@samthor</a></p>
<textarea id="input"></textarea>

<div class="extent"></div>
</body>


Enter fullscreen mode Exit fullscreen mode

2. JavaScript listener

By listening to the selectionchange event, we can detect whether both elements are selected in the same gesture. Since our extent elements are transparent, fixed, and have no width, a user can't select them by dragging over them.

The code looks like this:



document.addEventListener('selectionchange', (ev) => {
  const isExtent = (node) => {
    return node instanceof Element && node.classList.contains('extent');
  };

  // check the selection extends over two extent nodes (top and bottom)
  const s = window.getSelection();
  if (s.anchorNode === s.focusNode || !isExtent(s.anchorNode) || !isExtent(s.focusNode)) {
    return;
  }

  // clear page's selection (this isn't perfect and a user may see
  // a flash of selection anyway- use selectstart + rAF to fix this)
  s.removeAllRanges();
  // TODO: focus code goes here
});


Enter fullscreen mode Exit fullscreen mode

3. Focus 🔍

Finally, you can focus on something! After the call to s.removeAllRanges() above, run something like:



  const main = document.querySelector('textarea#main');  // or whatever you want to focus
  main.focus();
  main.setSelectionRange(0, main.value.length);


Enter fullscreen mode Exit fullscreen mode

This programatically selects the entire contents of textarea#main. You might alternatively want to do something else creative with the Select All gesture! Who knows! 🤔

Thanks!

Here's a CodePen that puts the code together for a demo. 👍

A related concept is user-select: none, which disables selection on certain parts of your page. While a complex web app with app-like flows could use it, it's not a solution to the "Select All" problem.

This is just one of many gestures that we can leverage: e.g., this is a follow-up to a post called Native Undo & Redo for the Web, which covers how to insert custom events in the undo stack. And, if you'd like to detect opening "Find" in a page, watch this space—the openfind event is coming soon.

4 👋

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .