Hello,
Firefox and Chromium do not treat mouse side buttons the same way.
The physical button codes are:
X1 / Browser Back button → MouseEvent.button === 3
X2 / Browser Forward button → MouseEvent.button === 4
Their MouseEvent.buttons bit values are 8 and 16.
The code below has a capture-phase listener for pointerdown, mousedown, mouseup, auxclick, and click. It also logs calls to preventDefault(), stopPropagation(), and stopImmediatePropagation().
Under Chromium, a press on the Back side button yields:
pointerdown → button: 3, buttons: 8
mousedown → button: 3, buttons: 8
mouseup → button: 3, buttons: 0
auxclick → button: 3, buttons: 0
The log also shows calls from the app to preventDefault(), stopPropagation(), and stopImmediatePropagation() for these events.
Under Firefox, with the same code present, a press on X1 (button === 3) or X2 (button === 4) yields no event record and no interception record in the console.
Does Firefox intercept the Browser Back and Browser Forward mouse buttons at browser level before DOM MouseEvent or PointerEvent events go to web content?
If yes, does Firefox offer a way for a web app to use this map?
button 3 → in-app Back
button 4 → in-app Forward
If this is a bug, please fix it. If Firefox does this by design, please remove this limit. This limit blocks web apps from use of standard X1/X2 mouse buttons for in-app navigation.
Diagnostic code:
(() => {
window.mouseEventProbeStop?.();
const types = ["pointerdown", "mousedown", "mouseup", "auxclick", "click"];
const original = {
preventDefault: Event.prototype.preventDefault,
stopPropagation: Event.prototype.stopPropagation,
stopImmediatePropagation: Event.prototype.stopImmediatePropagation
};
const dataOf = (e) => ({
type: e.type,
button: e.button,
buttons: e.buttons,
defaultPrevented: e.defaultPrevented,
trusted: e.isTrusted,
target: e.target?.tagName || String(e.target)
});
const isSideButton = (e) =>
e.button >= 3 || (e.buttons & 8) || (e.buttons & 16);
Event.prototype.preventDefault = function () {
if (isSideButton(this)) {
console.log("🟡 preventDefault çağrıldı", dataOf(this));
}
return original.preventDefault.call(this);
};
Event.prototype.stopPropagation = function () {
if (isSideButton(this)) {
console.log("🟠 stopPropagation çağrıldı", dataOf(this));
}
return original.stopPropagation.call(this);
};
Event.prototype.stopImmediatePropagation = function () {
if (isSideButton(this)) {
console.log("🔴 stopImmediatePropagation çağrıldı", dataOf(this));
}
return original.stopImmediatePropagation.call(this);
};
const listener = (e) => {
if (isSideButton(e)) {
console.log("🟢 Sayfaya gelen olay", dataOf(e));
}
};
types.forEach((type) => {
window.addEventListener(type, listener, true);
});
window.mouseEventProbeStop = () => {
types.forEach((type) => {
window.removeEventListener(type, listener, true);
});
Event.prototype.preventDefault = original.preventDefault;
Event.prototype.stopPropagation = original.stopPropagation;
Event.prototype.stopImmediatePropagation = original.stopImmediatePropagation;
console.log("Fare olay teşhisi kapatıldı.");
};
console.clear();
console.log("🟢 Fare olay teşhisi aktif. Geri ve ileri yan tuşlara bas.");
console.log("Bitince: mouseEventProbeStop()");
})();