Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 20 You must be signed in to star a gist
  • Fork 5 You must be signed in to fork a gist
  • Save shimondoodkin/1081133 to your computer and use it in GitHub Desktop.
Save shimondoodkin/1081133 to your computer and use it in GitHub Desktop.
WebKit contentEditable focus bug workaround
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>WebKit contentEditable focus bug workaround</title>
<script type='text/javascript' src='http://code.jquery.com/jquery-1.6.2.js'></script>
<script type='text/javascript'>
//<![CDATA[
$(function(){
// WebKit contentEditable focus bug workaround:
if(/AppleWebKit\/([\d.]+)/.exec(navigator.userAgent)) {
var editableFix = $('<input style="width:1px;height:1px;border:none;margin:0;padding:0;" tabIndex="-1">').appendTo('html');
$('[contenteditable]').blur(function () {
editableFix[0].setSelectionRange(0, 0);
editableFix.blur();
});
}
});
//]]>
</script>
</head>
<body>
If you use contentEditable DIVs in your web application then this, is for you. <br>
In WebKit based browsers there is a bug, of not passing focus to non contentEditable <br>
elements from contentEditable elements. When clicking outside the contentEditable element then when <br>
you for example type it still types in the content editable element. <br>
the blur on contentEditable elements is not happening correctly <br>
so we developed a workaround for this. you can see it here <br>
<br>
<br>
What steps will reproduce the problem? <br>
1. open this page: http://jsfiddle.net/jAhCa/
2. use two elements: a contenteditable div and a checkbox <br>
3. click on the div <br>
4. click on the checkbox <br>
5. press "right", "left" key see the focus is still on contenteditable div <br>
6. related to issues: http://code.google.com/p/chromium/issues/detail?id=89026
<br>
simple html to play around with: <br>
<br>
<div contenteditable="true">hel<input type="checkbox"/>lo</div>
<div contenteditable="true">hello2</div>
<input type="checkbox"/>
<input type="text"/>
</body>
</html>
@shimondoodkin
Copy link
Author

non jquery version looked like this, it is little different:

if(/AppleWebKit\/([\d.]+)/.exec(navigator.userAgent)) { // detect webkit
    var refocus_prevtarget = null;
    function refocusContentEditable() { 
        var curelement=window.event.target;
        if(refocus_prevtarget) { // if we have a previous element
            // if previous element was contentEditable and the next isn't then:
            if(refocus_prevtarget.contentEditable == 'true' && curelement.contentEditable !== 'true') {
                document.getElementById('editableFix').setSelectionRange(0, 0); // set caret focus to an element that handles caret focus correctly.
                curelement.focus(); // focus the wanted element.
            }
        }
        refocus_prevtarget=curelement;
    }
    document.addEventListener("click", refocusContentEditable, false); // add global click handler
}
<input id="editableFix" style="width:1px;height:1px;border:none;margin:0;padding:0;" tabIndex="-1">

@reedling78
Copy link

Worked like a champ! Thanks!

@smancke
Copy link

smancke commented Nov 6, 2013

@shimondoodkin:

you made my day!

@benweet
Copy link

benweet commented Apr 19, 2014

Thanks a lot.

@sirbrillig
Copy link

Thanks! This was very helpful.

Here's a slightly different version to prevent scrolling and without leaving extra elements in the page (this can be called multiple times):

$( element ).on( 'blur', function() {
  $( element ).off( 'blur' );
  var editableFix = jQuery('<input style="width:1px;height:1px;border:none;margin:0;padding:0;" tabIndex="-1">').appendTo( element );
  editableFix.focus();
  editableFix[0].setSelectionRange(0, 0);
  editableFix.blur();
  editableFix.remove();
}

@emertechie
Copy link

Thanks man, solved the issue for me

@SimeonC
Copy link

SimeonC commented Oct 30, 2014

For the non-jquery version I found I had to use mousedown rather than click, otherwise it breaks when you try to select some text elsewhere on the page by dragging.

@rdetert
Copy link

rdetert commented Jan 15, 2015

Doesn't seem to work in Safari 6, I must be doing it wrong.

Copy link

ghost commented Mar 19, 2015

So must I, as none of the suggestions work for me, either. At least in the work that I'm doing.

@fkenji
Copy link

fkenji commented Sep 21, 2015

Maybe we should add a disabled attribute to the input element?

var editableFix = $('<input disabled style="width:1px;height:1px;border:none;margin:0;padding:0;" tabIndex="-1">').appendTo('html');

If we don't have it on, the browser jumps to the bottom of the screen after unfocusing the content editable div and typing any character.

@icarus-sullivan
Copy link

Fantastic! Saved me 5 days of headache!!!

@dtruffaut
Copy link

dtruffaut commented Jun 24, 2019

I confirm this trick works, I did:

.search-input-focus-fix {
  display: none;
}

...

<div class=search-input contenteditable=true></div>
<input class=search-input-focus-fix tabIndex='1'>

...

// Focus an input (by setting a selection range)
document.querySelector('.search-input-focus-fix').setSelectionRange(0, 0);

// Focus the contenteditable element
document.querySelector('.search-input').focus();

It also works, if you create a temporary input:

// Focus an input (by setting a selection range)
document.createElement('input').setSelectionRange(0, 0);

// Focus the contenteditable element
document.querySelector('.search-input').focus();

@afloesch
Copy link

Another solution to this is to trap the mouse down event (the first to fire of the Mouse type events from a mouse click), and preventDefault() on the event. Must be trapped on mouse down or the selection and range will be different if handled later. This should work in any version of Safari.

For example:

<span onclick="document.execCommand('bold', false);" onmousedown="event.preventDefault();">
  <i class="material-icons">format_bold</i>
</span>

@brunoinds
Copy link

Another solution to this is to trap the mouse down event (the first to fire of the Mouse type events from a mouse click), and preventDefault() on the event. Must be trapped on mouse down or the selection and range will be different if handled later. This should work in any version of Safari.

For example:

<span onclick="document.execCommand('bold', false);" onmousedown="event.preventDefault();">
  <i class="material-icons">format_bold</i>
</span>

That's the best solution for avoid unfocus element on Webkit.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment