1

I want to select all text inside a div via a single click/tap. See example code (jsFiddle):

document.getElementById('target').addEventListener('click', function (event) {
  setTimeout(function() {
    window.getSelection().selectAllChildren(
            document.getElementById('target')
    )
  }, 100);
});
<div id="target">
  <span>click to select all </span>
  <span>text</span>
</div>

It works on desktop, but not properly on iOS using Safari (likely same problem on Android as well).

As you can see, I added a setTimeout() in an attempt to capture the mobile tap, but it only works after taping many times or focusing on the div via a long tap.

How can I make it select the full text with a single tap on iOS using pure JS?

Edit 1: Setting touchstart as event trigger might work, but avoiding it as it can be triggered by scrolling down the page and accidentally touching the element.

Edit 2: Making a bounty for a tested solution which works on iOS and mobile in general.

Henrik Petterson
  • 6,862
  • 20
  • 71
  • 155
  • Have you tried `document.getElementById('target').addEventListener('touchstart', ...)`? – Mr. Polywhirl Jan 12 '23 at 17:21
  • @Mr.Polywhirl How would this be different on mobile specifically? I believe this will trigger it even if the user is scrolling by the element, rather than tapping on it (and releasing), if you get my point. =) – Henrik Petterson Jan 12 '23 at 17:44

3 Answers3

2

Instead of JS you could use a CSS only approach with user-select: all; (MDN)

#target {
  /*
  -webkit-touch-callout: all; /* iOS Safari /
  -webkit-user-select: all; /* Safari /
  -khtml-user-select: all; /* Konqueror HTML /
  -moz-user-select: all; /* Firefox /
  -ms-user-select: all; /* Internet Explorer/Edge /
  */
  user-select: all;
}
<div id="target">
  <span>click to select all </span>
  <span>text</span>
</div>

Be aware that if you want users to be able to select a custom range within your #target it won't let them do that with this approach as it will "force" an all-text selection. But if that is not an issue/requirement the CSS approach is more elegant (IMHO) and should work cross device/platform (if you need to support really old browsers, you can use vendor prefixes as well).

exside
  • 3,736
  • 1
  • 12
  • 19
  • 1
    Sadly, even using the `-webkit-` prefix, this doesn't work on iOS Safari. Feel free to test this [jsFiddle](https://jsfiddle.net/sue1bgdj/). – Henrik Petterson Jan 17 '23 at 09:24
  • Unfortunately I don't have an iPhone/iOS device to test, but I'm surprised, based on MDN browser support table it should be supported, but you could try `-webkit-touch-callout: all;`, that's what it was called (for iOS/Safari) before user-select was standardized. – exside Jan 17 '23 at 16:49
  • Thanks but still didn't work on iOS. I think a JS solution is the only way sadly. – Henrik Petterson Jan 18 '23 at 14:08
1

I actually like @exside's solution, but cross platform support is sadly poor.

Anyways, the solution.

We'll use the window.getSelection api which returns a Selection object and move on from there.

const selectableTarget = document.getElementById('target');

selectableTarget.onclick = () => {
  // Get reference to the Selection object and remove all selected ranges
  const selection = window.getSelection();
  selection.removeAllRanges();

  // Create a new range and select the target node
  const range = document.createRange();
  range.selectNode(selectableTarget);

  // Add the range to the selection
  selection.addRange(range);
};
<div id="target">
  <span>Select me please</span>
</div>
Kitanga Nday
  • 3,517
  • 2
  • 17
  • 29
  • 2
    Sadly, this did not work on Safari iOS. Feel free to test it yourself: https://jsfiddle.net/y49qz1w8/ -- I have regardless marked this as fixed as the bounty time ran out. :/ – Henrik Petterson Jan 24 '23 at 14:19
  • Hold on, I'll find the cross platform variant. – Kitanga Nday Jan 25 '23 at 06:58
  • 2
    @HenrikPetterson it works on chrome android, so I'll just find how to do this on iOS – Kitanga Nday Jan 25 '23 at 07:00
  • 2
    I will be very impressed if you do! Only example I see working is for [selecting text in an input field](https://stackoverflow.com/a/33195028/2696687), but didn't manage to adapt that into my code scenario. From my research, iOS doesn't generally show the selection until the user _manually_ selects the text. Let me know if you pull it off! – Henrik Petterson Jan 25 '23 at 08:55
  • Quick question are you using iOS12? – Kitanga Nday Jan 25 '23 at 22:04
  • 1
    I use iOS16.3 which is the latest version. Sorry about the late response, didn't see your comment earlier. Did you figure out a solution to this yet? Thanks! – Henrik Petterson Jan 31 '23 at 10:29
  • @HenrikPetterson, no it's cool, I was only able to get my hands on an iOS device today, my friend has one, also with iOS 16. Code didn't work. Now I need to test it on his phone and see what I can do – Kitanga Nday Feb 01 '23 at 21:35
1

You can try window selection APIs or document.selection API for old browsers: -

document.getElementById('target').addEventListener('click', function (event) {
if (window.getSelection && document.createRange) { //Browser compatibility
      sel = window.getSelection();
      if(sel.toString() == ''){ //no text selection
      window.setTimeout(function(){
        range = document.createRange(); //range object
        range.selectNodeContents(event.target); //sets Range
        sel.removeAllRanges(); //remove all ranges from selection
        sel.addRange(range);//add Range to a Selection.
      },100);
        }
    }else if (document.selection) { //older ie
        sel = document.selection.createRange();
        if(sel.text == ''){ //no text selection
            range = document.body.createTextRange();//Creates TextRange object
            range.moveToElementText(el);//sets Range
            range.select(); //make selection.
        }
    }
  });

jsfiddle: https://jsfiddle.net/u4yhn3sk/41/

Sumit Parakh
  • 1,098
  • 9
  • 19