So i am using a <span>
with contenteditable="true"
. onkeydown
generates new elements with the key pressed as text. I use preventDefault()
to not show the pressed character in the input field. If "backspace" is pressed, the last new element ist deleted.
It works really well on desktop browsers, but it has an issue on mobile. When testing firefox for android, if I type some letters and then press backspace, none of the events are triggered in js. The virtual keyboard (default and swiftkey tested) somehow keep the last letters and only remove them within the keyboard - only after these are all gone the events get passed to js again.
It is not easy to describe - the scribble shows it. The problem only exists on mobile!!
Resetting the "contenteditable" attribute prevents this behaviour but it also flashes the keyboard, which is not ideal.
//EDIT: fiddle is updated: catching 229, reset caret position, reset input content to " "
let editableSpan = document.querySelector('#inp');
editableSpan.onkeydown = function(e){
console.log('key pressed', e.which, e.key);
if(e.key === 'Backspace' || e.key === 'Process'){
var keyEls = document.querySelectorAll('#out .kbd');
keyEls.length > 0 && keyEls[keyEls.length - 1].remove();
}else if(e.key.length === 1){
var keyEl = document.createElement('span');
keyEl.classList.add('kbd');
keyEl.textContent = e.key;
document.querySelector('#out').append(keyEl);
}
e.preventDefault();
}
editableSpan.onkeyup = function(e){
var letterInp = document.querySelector('#inp');
var selection = window.getSelection();
var range = document.createRange();
letterInp.innerHTML = ' ';
range.setStart(letterInp, letterInp.childNodes.length);
range.collapse(true);
selection.removeAllRanges();
selection.addRange(range);
}
#inp {
background-color: goldenrod;
border: solid 3px black;
}
.kbd {
display:inline-block;
background-color:darkgrey;
font-size: 2em;
padding: .5em;
margin-right: .3em;
margin-top: .3em;
border-radius:.3em;
font-style:monospace;
}
<span id="out"></span>
<span class="kbd" id="inp" contenteditable="true"> </span>
So i am using a <span>
with contenteditable="true"
. onkeydown
generates new elements with the key pressed as text. I use preventDefault()
to not show the pressed character in the input field. If "backspace" is pressed, the last new element ist deleted.
It works really well on desktop browsers, but it has an issue on mobile. When testing firefox for android, if I type some letters and then press backspace, none of the events are triggered in js. The virtual keyboard (default and swiftkey tested) somehow keep the last letters and only remove them within the keyboard - only after these are all gone the events get passed to js again.
It is not easy to describe - the scribble shows it. The problem only exists on mobile!!
Resetting the "contenteditable" attribute prevents this behaviour but it also flashes the keyboard, which is not ideal.
//EDIT: fiddle is updated: catching 229, reset caret position, reset input content to " "
let editableSpan = document.querySelector('#inp');
editableSpan.onkeydown = function(e){
console.log('key pressed', e.which, e.key);
if(e.key === 'Backspace' || e.key === 'Process'){
var keyEls = document.querySelectorAll('#out .kbd');
keyEls.length > 0 && keyEls[keyEls.length - 1].remove();
}else if(e.key.length === 1){
var keyEl = document.createElement('span');
keyEl.classList.add('kbd');
keyEl.textContent = e.key;
document.querySelector('#out').append(keyEl);
}
e.preventDefault();
}
editableSpan.onkeyup = function(e){
var letterInp = document.querySelector('#inp');
var selection = window.getSelection();
var range = document.createRange();
letterInp.innerHTML = ' ';
range.setStart(letterInp, letterInp.childNodes.length);
range.collapse(true);
selection.removeAllRanges();
selection.addRange(range);
}
#inp {
background-color: goldenrod;
border: solid 3px black;
}
.kbd {
display:inline-block;
background-color:darkgrey;
font-size: 2em;
padding: .5em;
margin-right: .3em;
margin-top: .3em;
border-radius:.3em;
font-style:monospace;
}
<span id="out"></span>
<span class="kbd" id="inp" contenteditable="true"> </span>
Share Improve this question edited Feb 5 at 18:01 Maze asked Feb 4 at 22:34 MazeMaze 1231 silver badge6 bronze badges 7 | Show 2 more comments
1 Answer
Reset to default 0With some pointers from @Yogi I got a working solution.
issue 1: no events fired in js - only happens when caret is placed before "space" -> always set caret position to end of element
issue 2: key=229 is returned in keydown -> handle it the same as backspace and reset the inputs content to " " in onkeyup
e.key
and note.which
, as it was deprecated... oh, long time ago. Some browsers may still support it, but you cannot rely on it. Please usee.key
and tell us if it solves the problem. Thee.key
value should be"Backspace"
. – Sergey A Kryukov Commented Feb 4 at 22:59