This page illustrates a bug in Mozilla Firefox v68+.
The following input
has 2 event listeners, one for keydown
and one for
input
. In browsers, when pressing keys, the keydown
event
will fire, then the input
event will fire. This is the case for the
delete
key as well. Under normal circumstances, if the value
of the input is modified in the event listener for keydown
, the cursor
selection will be put at the end of the input and the input
event will
not fire. You can mitigiate this by setting the selection of the cursor after the
value
is modified. For regular keys, this works just fine in all browsers.
However, in the latest version of Firefox, when the delete
key (to remove the character after the cursor, fn + delete on a Mac, just delete on a PC) is used,
the input
event never fires, even when adjusting the selection.
For an example of the expected behavior, do the following in Chrome.
o
and p
in the input below.b
and you should see a log that the keydown
event fired
and the input
event fired.delete
and you should see both events fire.For an example of the buggy behavior, do the following in Firefox 68+.
o
and p
in the input below.b
, and like the expected behavior example, and you should see a log
that the keydown
event fired and the input
event fired.delete
and you should see that the input
event
never fires and the delete key never deletes the character (you can also see that the keydown
transform of
uppercasing everything is applied, but the input
transform of
lowercasing everything is not).delete
again, it does fire the input
event and deletes the p
character (presumably
because the input
's value did not actually change, it went from the uppercase
version of the string to the uppercase version).
Admittedly, this is a bit of a contrived example. Where my team is seeing this behavior
is in our input formatting library to automatically add spaces to credit and debit card numbers.
Our integration tests started failing in Firefox 68 because the 5
in
1234 56
code no longer be deleted with the delete key, because the input
event would not fire as transforms were applied to the input's value.
var input = document.getElementById('input');
var log = document.getElementById('log');
input.addEventListener('keydown', function () {
writeLog('keydown event fired');
applyTransform(function (val) {
return val.toUpperCase();
});
});
input.addEventListener('input', function () {
writeLog('input event fired');
applyTransform(function (val) {
return val.toLowerCase();
});
});
function applyTransform(transform) {
var start = input.selectionStart;
var end = input.selectionEnd;
input.value = transform(input.value);
input.setSelectionRange(start, end);
}
function writeLog(message) {
log.innerText = log.innerText + message + '\n';
}