290

On IE I can do this with the (terribly non-standard, but working) jQuery

if ($.browser.msie)
    $(document).keydown(function(e) { if (e.keyCode == 8) window.event.keyCode = 0;});

But is it possible to do in a way which works on Firefox, or in a cross-browser way for a bonus?

For the record:

$(document).keydown(function(e) { if (e.keyCode == 8) e.stopPropagation(); });

does nothing.

$(document).keydown(function(e) { if (e.keyCode == 8) e.preventDefault(); });

solves the problem, but renders the backspace key unusable on the page, which is even worse than the original behaviour.

EDIT: The reason I do this is that I'm not creating a simple web page but a large application. It is incredibly annoying to lose 10 minutes of work just because you pressed backspace in the wrong place. The ratio of preventing mistakes vs. annoying users should be way above 1000/1 by preventing the backspace key from navigating back.

EDIT2: I'm not trying to prevent history navigation, just accidents.

EDIT3: @brentonstrines comment (moved here since the question is so popular): This is a long-term 'fix', but you could throw your support behind the Chromium bug to change this behavior in webkit

John Weisz
  • 30,137
  • 13
  • 89
  • 132
erikkallen
  • 33,800
  • 13
  • 85
  • 120
  • 2
    Why do you want to do this? Keyboard shortcuts are important for power users and disabled users alike to effectively use your site. – pkaeding Sep 29 '09 at 22:12
  • Ditto; it's kinda an odd thing to do... unless you have some VERY case-specific usage for the backspace key in your app and were trapping it for yourself. If you're trying to disable the back functionality in the browser's history, I don't believe there is ANY way to reliably (or otherwise?) do that. – eidylon Sep 29 '09 at 22:18
  • 142
    Because the backspace key is overloaded. You might not have noticed it, but you probably use it all the time for erasing letters you've just typed in a text field. Some of my customers have been having trouble with that causing the page to go back, so this is useful information. Nobody but you clowns knows that backspace is *supposed* to go back a page. That's something I never knew, and it's outright hostile behavior for a browser to have. I think all pages should disable that behavior. – Breton Sep 29 '09 at 22:32
  • 83
    Why do people think this is odd? Using backspace for navigation is a really dumb shortcut! there are so many text fields that users might want to delete text from - imagine having a long SO answer, switching to another window to check something, and then you come back and mis-click the edit area, press backspace to remove a word and suddenly the browser goes back a page and you've potentially lost everything you just wrote. – Peter Boughton Sep 29 '09 at 22:33
  • 59
    Why I want to do this? I'm not creating a web site but a web application. Some input fields are read-only in which case they look editable, but if you press backspace you leave the page. The ratio of backspace presses intending to navigate back vs. backspace presses trying to erase something is probably much less than 1 / 1000. – erikkallen Sep 30 '09 at 08:31
  • Erik, read-only fields should not look editable - why not use a bit of jQuery to re-style read-only fields? – Peter Boughton Oct 01 '09 at 18:01
  • @Peter: To use the same argument as the other people: It's standard so it should be done. To use a real argument: Yes, it would probably be a good idea, but I still want to prevent the accidents. – erikkallen Oct 01 '09 at 20:32
  • 43
    The question is how to do this, not your opinion on whether it is a good idea or not. Without knowing the details of the project your opinions are meaningless. My client has specifically requested this behavior for one of my projects and a real answer rather than "Why would you ever want to do that?" would be helpful. – None Dec 07 '12 at 01:59
  • 7
    This is a long-term 'fix', but you could throw your support behind the Chromium bug to change this behavior in webkit: http://code.google.com/p/chromium/issues/detail?id=144832 – brentonstrine Dec 18 '12 at 00:23
  • I am using alt+left as a back button so I am ready for disabling backspace as a back button. Alas, [IMDB](http://imdb.com) has hijacked the arrow keys so I have to use backspace there. – diynevala May 21 '14 at 05:04
  • 2
    Google included this dumb-ass key mapping in Chrome, but they also disabled the mapping in their search results page, making backspace act as backspace should even when the query text field is not focused. Even the companies that make the browsers don't like this key binding. – Sam Watkins May 21 '15 at 05:12
  • The answers to this question are not good enough. They are too complex, might not catch all cases of accidental navigation, and might disable the normal "backspace" function in unusual input fields. Ideally, the companies that make the browsers should disable this bone-headed key binding by default. Until that might happen, I suggest to simply confirm navigation if any text has been entered into form fields. The second answer here looks good: http://stackoverflow.com/questions/5102602/confirm-to-leave-the-page-when-editing-a-form-with-jquery – Sam Watkins May 21 '15 at 05:58
  • I created a NPM project with a clean version of the currently accepted answer: https://github.com/slorber/backspace-disabler – Sebastien Lorber Aug 06 '15 at 18:14
  • Google plans to [remove backspace navigation](http://arstechnica.com/business/2016/05/google-backspace-navigation-chrome-52/) on 26-July-2016. It's currently available in Chrome 52 (beta channel). – tony19 Jun 11 '16 at 23:35
  • 2
    Maybe browsers can also map `delete` to go forward a page? – Mark K Cowan Sep 24 '16 at 14:20
  • A Simple but elegant solution that may or may not work for you.. onkeydown="alert('Read Only Field!'); return false;" or onkeydown="return false;" – Deathstalker Oct 20 '16 at 16:07
  • What disturbs me the most about all of this is that Breton's comment has the most likes. Obviously there are many "software developers" out there that are too closed-minded to see any possible reason why you might need backspace navigation disabled. For those who are not closed-minded, maybe I can give some insight: if the user types a lot of data on the page, or they otherwise set the page up in such a way that a navigation change would lose their work, a simple, stupid backspace navigation "mishap" by the user could be an extremely frustrating loss of time and effort. – Andrew Apr 20 '17 at 12:38
  • Let me remind all of you that it is our **JOB** to make our software as user-friendly as possible. 90's grade software just won't cut it anymore. And *if you can't give a darn as to whether your software is top-notch or whether your users are content, you should quit and find a different job*. Do us all a favor, developer and end-user alike. – Andrew Apr 20 '17 at 12:40

33 Answers33

340

This code solves the problem, at least in IE and Firefox (haven't tested any other, but I give it a reasonable chance of working if the problem even exists in other browsers).

// Prevent the backspace key from navigating back.
$(document).unbind('keydown').bind('keydown', function (event) {
    if (event.keyCode === 8) {
        var doPrevent = true;
        var types = ["text", "password", "file", "search", "email", "number", "date", "color", "datetime", "datetime-local", "month", "range", "search", "tel", "time", "url", "week"];
        var d = $(event.srcElement || event.target);
        var disabled = d.prop("readonly") || d.prop("disabled");
        if (!disabled) {
            if (d[0].isContentEditable) {
                doPrevent = false;
            } else if (d.is("input")) {
                var type = d.attr("type");
                if (type) {
                    type = type.toLowerCase();
                }
                if (types.indexOf(type) > -1) {
                    doPrevent = false;
                }
            } else if (d.is("textarea")) {
                doPrevent = false;
            }
        }
        if (doPrevent) {
            event.preventDefault();
            return false;
        }
    }
});
Jorge Fuentes González
  • 11,568
  • 4
  • 44
  • 64
erikkallen
  • 33,800
  • 13
  • 85
  • 120
  • 1
    added check for Text INPUTs only, if you were focused on a Button the backspace was working. – Glennular Mar 07 '12 at 15:33
  • 7
    As Hemlock stated - check for `d.type.toUpperCase() === 'PASSWORD'` as well. Otherwise looks good – stevendesu Jun 04 '12 at 22:43
  • 17
    Since you're already using jQuery `if( $(d).is( ":input" ) )...` – Paul Alexander Oct 12 '12 at 21:24
  • 1
    This prevents backspace from working in new HTML5 input types (like number) in browsers that recognize those types (like Chrome). If you modify the if() and instead of only blocking specific types, reverse the logic to allow backspace on all inputs except submits reset, button, checkbox, radio, image, etc. it's a bit more future proof. – Richard Davies Feb 14 '13 at 19:29
  • I do roughly this except I also require `$('.ui-dialog').length != 0` before blocking the default behaviour. Only need to do so when a dialog is open. – Daniel Earwicker Feb 26 '13 at 11:19
  • 1
    @PaulAlexander using `if( $(d).is( ":input" ) )` doesn't work because if the user selects a dropdown input and then press backspace the undesired behaviour still occurs. – intrepidis Mar 20 '13 at 11:25
  • 1
    @erikkallen, as of HTML5, `contentEditable` attribute has been [standardized by WHATWG](http://www.whatwg.org/specs/web-apps/current-work/multipage/editing.html#contenteditable) and should be accounted for. – tomsseisums May 16 '13 at 14:57
  • Link to solution http://www.telerik.com/community/code-library/aspnet-ajax/general/disable-backspace-from-master-page.aspx – Marek Bar Jul 31 '13 at 21:20
  • @MarekBar The teleric solution is pretty much identical to the one in this answer, but doesn't handle readonly/disabled controls (which this answer does. I need to add 'FILE' to the whitelisted things, though. – erikkallen Aug 01 '13 at 16:04
  • 23
    It sucks that this has to be a whitelist, rather than being able to blacklist the "back" functionality. You may want to add a check for `d.isContentEditable` in here. – iono Sep 12 '13 at 05:09
  • to complete the Paul Alexander comment, this is the full working line with jquery : `if ( $(d).is(":text") || $(d).is(":password") || $(d).is(":file") || $(d).is("textarea") ) {` But it won't work for html5 new editable elements, and I don't understand Chris Nash comment… – Matthieu Jan 21 '14 at 12:48
  • I also added the condition for NUMBER for the HTML-5 number input. Although I have not looked into the contentEditable attribute yet (this may cover it) – jadrake Apr 15 '14 at 16:24
  • 1
    Probably worth [namespacing](http://api.jquery.com/on/) the `unbind` and `bind` calls so you don't wipe out things that might already live on `keydown` *anywhere in the document*. ;^) – ruffin Jul 08 '14 at 17:36
  • 4
    I created a NPM project with a clean version of the currently accepted answer: https://github.com/slorber/backspace-disabler (it also support contenteditables and has no dependency) – Sebastien Lorber Aug 06 '15 at 18:14
  • This is working well, but I found one place that it doesn't. On Chrome, when a select drop-down is open (about to select an option) and the backspace is pressed, it will navigate back. I realize the likelihood of someone pressing the backspace when the select drop-down is open is small, but should be noted. – nwolybug Jul 12 '16 at 14:00
  • Best answer in mid 2016, but it would best if the popstate event contained information about *what* popped the state so you can cancel it. – B T Jul 23 '16 at 23:23
66

This code works on all browsers and swallows the backspace key when not on a form element, or if the form element is disabled|readOnly. It is also efficient, which is important when it is executing on every key typed in.

$(function(){
    /*
     * this swallows backspace keys on any non-input element.
     * stops backspace -> back
     */
    var rx = /INPUT|SELECT|TEXTAREA/i;

    $(document).bind("keydown keypress", function(e){
        if( e.which == 8 ){ // 8 == backspace
            if(!rx.test(e.target.tagName) || e.target.disabled || e.target.readOnly ){
                e.preventDefault();
            }
        }
    });
});
thetoolman
  • 2,144
  • 19
  • 11
  • 1
    Please test my example, you may wish to update your code accordingly. – Biff MaGriff Nov 21 '11 at 22:46
  • 10
    I prefer this over @erikkallen's solution because it's cleaner. However, I wanted submit buttons, radio buttons, and check boxes to also be ignored, so I changed the if() to this: `if(!rx.test(e.target.tagName) || $(e.target).is(':checkbox') || $(e.target).is(':radio') || $(e.target).is(':submit') || e.target.disabled || e.target.readOnly )` – Matthew Clark Nov 20 '12 at 17:46
  • @thetoolman, see my comment on erikallen's answer. This should also account for `contentEditable`. – tomsseisums May 16 '13 at 14:59
  • 10
    @MaffooClock: you can be more concise with `.is(':checkbox,:radio,:submit')` – cdmckay Feb 22 '14 at 22:17
  • 1
    @cdmckay: I can't believe I didn't write it that way in the first place. Thanks for cleaning that up for us all :) – Matthew Clark Feb 24 '14 at 03:20
  • I think this without the rx check but with @VladimirKornea answer is the best most adaptable answer now that prettymuch anything can be editable – cmbarbu Dec 15 '15 at 23:41
42

The other answers here have established that this cannot be done without whitelisting elements in which Backspace is allowed. This solution is not ideal because the whitelist is not as straightforward as merely textareas and text/password inputs, but is repeatedly found to be incomplete and needing to be updated.

However, since the purpose of suppressing the backspace functionality is merely to prevent users from accidentally losing data, the beforeunload solution is a good one because the modal popup is surprising--modal popups are bad when they are triggered as part of a standard workflow, because the user gets used to dismissing them without reading them, and they are annoying. In this case, the modal popup would only appear as an alternative to a rare and surprising action, and is therefore acceptable.

The problem is that an onbeforeunload modal must not pop up whenever the user navigates away from the page (such as when clicking a link or submitting a form), and we don't want to start whitelisting or blacklisting specific onbeforeunload conditions.

The ideal combination of tradeoffs for a generalized solution is as follows: keep track of whether backspace is pressed, and only pop up the onbeforeunload modal if it is. In other words:

function confirmBackspaceNavigations () {
    // http://stackoverflow.com/a/22949859/2407309
    var backspaceIsPressed = false
    $(document).keydown(function(event){
        if (event.which == 8) {
            backspaceIsPressed = true
        }
    })
    $(document).keyup(function(event){
        if (event.which == 8) {
            backspaceIsPressed = false
        }
    })
    $(window).on('beforeunload', function(){
        if (backspaceIsPressed) {
            backspaceIsPressed = false
            return "Are you sure you want to leave this page?"
        }
    })
} // confirmBackspaceNavigations

This has been tested to work in IE7+, FireFox, Chrome, Safari, and Opera. Just drop this function into your global.js and call it from any page where you don't want users to accidentally lose their data.

Note that an onbeforeunload modal can only be triggered once, so if the user presses backspace again, the modal will not fire again.

Note that this will not trigger on hashchange events, however in that context you can use other techniques to keep users from accidentally losing their data.

Val Kornea
  • 4,469
  • 3
  • 40
  • 41
  • 2
    I just went to add this same solution and saw this post at bottom of the page LOL. One difference I have is to set lastUserInputWasBackspace = false before the return "Are you sure..." statement, so you don't get the popup if you happen to click back button after already seeing the popup (so it's consistent with non-backspace-influenced behavior). – David Russell Jul 15 '14 at 02:46
  • 1
    @user2407309 I have removed my comment (not a complaint) about firefox not working with your solution. There was an issue with my debugger. My apologies for editing/breaking your code. I realize now that I overstepped my bounds (editing) forgive me. I am truly sorry and I meant no complaints to your wonderful solution to this problem. Again, my apologies. This code works well. I believe this is the best answer and I commend you for it. – Charles Byrne Nov 18 '14 at 18:39
  • 1
    This solution worked on my local machine, but when I moved it over, the client (at least some of them) lost functionality of half the application. I guess something is rejecting it, but I have no idea what. – Steve Mar 05 '15 at 20:11
  • @Steve, let me know what you find out, I am convinced that the problem is not with this function, but you've sown the seeds of doubt now, and only you can dispel them. – Val Kornea Mar 06 '15 at 04:06
  • @Vladimir No, the function works great for me, both running development and when I connect to the application from a browser via VPN. My guess would be that it is either some sort of security setting, or somehow connected to the fact that they are running the application inside of sharepoint. Unfortunately, I can't troubleshoot on their end, and they are happy enough with the "whitelist" solution (this wasn't that high a priority). If you are that concerned about it, I'll delete the comments, as I'm guessing this is pretty rare. – Steve Mar 06 '15 at 12:59
  • 1
    @Steve, rare or not, if there's a problem with the function, that information belongs here. I just want to know whether there really is a problem. – Val Kornea Mar 06 '15 at 13:18
  • Works well for me so far. Note that jQuery is a dependency (like most answers here). – Jay Jan 27 '16 at 23:48
  • This doesn't work for me. The window.on('beforeunload' ...) function never gets called when backspace is pressed. It hits the keydown handler, then the window location changes. Is there something in newer versions of Chrome that skip beforeunload handlers when backspace is pressed? – Andrew Feb 24 '16 at 19:25
  • @Andrew Perhaps you told Chrome not to show any more alerts for your site. – Val Kornea Feb 24 '16 at 23:11
  • @VladimirKornea Nope. I think it might be something related to using a backbone router in my case. – Andrew Feb 25 '16 at 18:06
  • 2
    Nice solution, but unfortunately, if a user accidentally presses backspace twice, it still navigates back. (at least on firefox) – Remco de Zwart Jan 03 '17 at 14:08
  • @andrew I think you're right about the backbone router, since it works by manipulating the hash fragment, and a mere fragment change doesn't trigger a page unload, since you're still semantically on the same page. – Val Kornea Feb 09 '18 at 22:46
28

A more elegant/concise solution:

$(document).on('keydown',function(e){
  var $target = $(e.target||e.srcElement);
  if(e.keyCode == 8 && !$target.is('input,[contenteditable="true"],textarea'))
  {
    e.preventDefault();
  }
})
Darwayne
  • 1,400
  • 14
  • 14
  • 1
    This is a lot more concise and from what I can tell works just as well. Why is it that the most popular answer has all those check for types of inputs, and seems more complicated? Is it more reliable? – Nearpoint Sep 12 '14 at 01:45
  • 1
    The most popular answer was the first one to answer the question, thus the high votes. – Darwayne Sep 12 '14 at 12:06
  • 4
    when readonly fields are focused delete still navigates back in chrome – Will D Nov 19 '14 at 21:16
16

Modification of erikkallen's Answer to address different input types

I've found that an enterprising user might press backspace on a checkbox or a radio button in a vain attempt to clear it and instead they would navigate backwards and lose all of their data.

This change should address that issue.

New Edit to address content editable divs

    //Prevents backspace except in the case of textareas and text inputs to prevent user navigation.
    $(document).keydown(function (e) {
        var preventKeyPress;
        if (e.keyCode == 8) {
            var d = e.srcElement || e.target;
            switch (d.tagName.toUpperCase()) {
                case 'TEXTAREA':
                    preventKeyPress = d.readOnly || d.disabled;
                    break;
                case 'INPUT':
                    preventKeyPress = d.readOnly || d.disabled ||
                        (d.attributes["type"] && $.inArray(d.attributes["type"].value.toLowerCase(), ["radio", "checkbox", "submit", "button"]) >= 0);
                    break;
                case 'DIV':
                    preventKeyPress = d.readOnly || d.disabled || !(d.attributes["contentEditable"] && d.attributes["contentEditable"].value == "true");
                    break;
                default:
                    preventKeyPress = true;
                    break;
            }
        }
        else
            preventKeyPress = false;

        if (preventKeyPress)
            e.preventDefault();
    });

Example
To test make 2 files.

starthere.htm - open this first so you have a place to go back to

<a href="./test.htm">Navigate to here to test</a>

test.htm - This will navigate backwards when backspace is pressed while the checkbox or submit has focus (achieved by tabbing). Replace with my code to fix.

<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js" type="text/javascript"></script>
<script type="text/javascript">

    $(document).keydown(function(e) {
        var doPrevent;
        if (e.keyCode == 8) {
            var d = e.srcElement || e.target;
            if (d.tagName.toUpperCase() == 'INPUT' || d.tagName.toUpperCase() == 'TEXTAREA') {
                doPrevent = d.readOnly || d.disabled;
            }
            else
                doPrevent = true;
        }
        else
            doPrevent = false;

        if (doPrevent)
            e.preventDefault();
    });
</script>
</head>
<body>
<input type="text" />
<input type="radio" />
<input type="checkbox" />
<input type="submit" />
</body>
</html>
Biff MaGriff
  • 8,102
  • 9
  • 61
  • 98
  • What browser did you see backspace press on radio|checkbox|submit -> back function ? I havent seen a browser do this.. – thetoolman Nov 21 '11 at 20:30
  • Internet Explorer 8 and Chrome – Biff MaGriff Nov 21 '11 at 22:28
  • 2
    I tried a number of other solutions in this thread, but this one worked well in all my situations and had the cleanest, easiest to understand code. Thank you. – Ezward Aug 26 '13 at 18:22
  • Did you try @Darwayne I am curious to know why that one is so short and this is is more complex, but both seem to work just the same for me – Nearpoint Sep 12 '14 at 01:54
  • Does this work on links? I have an ASP.Net application with an image button to remove an item. That's the only thing this hasn't worked on so far... – Steve Mar 05 '15 at 20:21
9

Based on the comments it appears you want to stop people losing information in forms, if they press backspace to delete but the field is not focused.

In which case, you want to look at the onunload event handler. Stack Overflow uses it - if you try to leave a page when you've started writing an answer, it pops up a warning.

DisgruntledGoat
  • 70,219
  • 68
  • 205
  • 290
  • 4
    sorry that was a rude comment. What I mean is, the user probably doesn't want to be berated for doing something they didn't even know was wrong. Why not just silently eat the key with an onkeydown? The goal is not to completely prevent the user from leaving the page, but to guard against this common mistake. In addition, pop up dialogues are not very effective, or useful. Users don't read them. Are you sure you want to leave the page? Okay! No wait wait, I didn't want to leave the page.. oops too late. – Breton Sep 30 '09 at 02:46
  • 3
    OK then take it or leave it. I think you're trying to over-engineer a problem that doesn't really exist, or at least isn't important. And in my experience, it's only power users who click "OK" on unfamiliar dialogs without reading them properly. ;) – DisgruntledGoat Sep 30 '09 at 10:49
  • @Disgruntled, You couldn't be more wrong. If you don't believe me, you could believe Raymond: http://blogs.msdn.com/oldnewthing/archive/2003/09/01/54734.aspx – erikkallen Sep 30 '09 at 11:13
  • 3
    Are you and Breton the same person? Anyway you kinda shot yourself in the foot there - the article says "the default answer is Cancel" so when seeing the dialog about leaving the page, they're going to press "Cancel" and therefore **not** leave the page. Though it should be noted that Chrome's options on that dialog are "Leave this page" and "Stay on this page" which are very clear. – DisgruntledGoat Sep 30 '09 at 12:13
  • 1
    No, he is not me, but I've come across that link before. I think the comments are hilarious. "What!? people ignore modal dialog boxes? We must find a way to make them even MORE persistent and annoying!". Really explains a lot about microsoft software. – Breton Oct 01 '09 at 03:29
  • 3
    @Disgruntled: No, I'm not Breton, and the point of the article is not "The default choice is..." but "users don't read anything." – erikkallen Oct 01 '09 at 20:34
  • I like this solution. I've been seeing it more in more on form pages too. It's like being asked if you want to save your changes when you close a file without saving. – None Sep 14 '15 at 20:26
9

Most of the answers are in jquery. You can do this perfectly in pure Javascript, simple and no library required. This article was a good starting point for me but since keyIdentifier is deprecated, I wanted this code to be more secure so I added ||e.keyCode==8 to the if statement. Also, the code wasn't working well on Firefox so I added return false; and now it works perfectly well. Here it is:

<script type="text/javascript">
window.addEventListener('keydown',function(e){if(e.keyIdentifier=='U+0008'||e.keyIdentifier=='Backspace'||e.keyCode==8){if(e.target==document.body){e.preventDefault();return false;}}},true);
</script>

This code works great because,

  1. It is in pure javascript (no library required).
  2. Not only it checks the key pressed, it confirms if the action is really a browser "back" action.
  3. Together with the above, user can type and delete text from input text boxes on the web page without any problems while still preventing the back button action.
  4. It is short, clean, fast and straight to the point.

You can add console.log(e); for your your test purposes, and hit F12 in chrome, go to "console" tab and hit "backspace" on the page and look inside it to see what values are returned, then you can target all of those parameters to further enhance the code above to suit your needs.

Tarik
  • 4,270
  • 38
  • 35
7

Stop from navigating this code works!

$(document).on("keydown", function (event) {        
   if (event.keyCode === 8) {
      event.preventDefault();
    }
  });

But for not to restricting text fields but others

$(document).on("keydown", function (event) {
  if (event.which === 8 && !$(event.target).is("input, textarea")) {
   event.preventDefault();
  }
});

To prevent it for specific field simply use

$('#myOtherField').on("keydown", function (event) {
  if (event.keyCode === 8 || event.which === 8) { 
   event.preventDefault(); 
  } 
});

Referring to this one below!

Prevent BACKSPACE from navigating back with jQuery (Like Google's Homepage)

Community
  • 1
  • 1
6

Combining solutions given by "thetoolman" && "Biff MaGriff"

following code seems to work correctly in IE 8/Mozilla/Chrome

$(function () {
    var rx = /INPUT|TEXTAREA/i;
    var rxT = /RADIO|CHECKBOX|SUBMIT/i;

    $(document).bind("keydown keypress", function (e) {
        var preventKeyPress;
        if (e.keyCode == 8) {
            var d = e.srcElement || e.target;
            if (rx.test(e.target.tagName)) {
                var preventPressBasedOnType = false;
                if (d.attributes["type"]) {
                    preventPressBasedOnType = rxT.test(d.attributes["type"].value);
                }
                preventKeyPress = d.readOnly || d.disabled || preventPressBasedOnType;
            } else {preventKeyPress = true;}
        } else { preventKeyPress = false; }

        if (preventKeyPress) e.preventDefault();
    });
}); 
CodeNepal
  • 732
  • 7
  • 11
4

Not sure why no-one's just answered this - seems like a perfectly reasonable technical question to ask whether it's possible.

No, I don't think there's a cross-browser way to disable the backspace button. I know it's not enabled by default in FF these days though.

brabster
  • 42,504
  • 27
  • 146
  • 186
4

I had a hard time finding a non-JQUERY answer. Thanks to Stas for putting me on the track.

Chrome: If you don't need cross browser support, you can just use a blacklist, rather than whitelisting. This pure JS version works in Chrome, but not in IE. Not sure about FF.

In Chrome (ver. 36, mid 2014), keypresses not on an input or contenteditable element seem to be targeted to <BODY>. This makes it possible use a blacklist, which I prefer to whitelisting. IE uses the last click target - so it might be a div or anything else. That makes this useless in IE.

window.onkeydown = function(event) {
    if (event.keyCode == 8) {
    //alert(event.target.tagName); //if you want to see how chrome handles keypresses not on an editable element
        if (event.target.tagName == 'BODY') {
            //alert("Prevented Navigation");
            event.preventDefault();
        }
    }
}  

Cross Browser: For pure javascript, I found Stas' answer to be the best. Adding one more condition check for contenteditable made it work for me*:

document.onkeydown = function(e) {stopDefaultBackspaceBehaviour(e);}
document.onkeypress = function(e) {stopDefaultBackspaceBehaviour(e);}

function stopDefaultBackspaceBehaviour(event) {
    var event = event || window.event;
    if (event.keyCode == 8) {
        var elements = "HTML, BODY, TABLE, TBODY, TR, TD, DIV";
        var d = event.srcElement || event.target;
        var regex = new RegExp(d.tagName.toUpperCase());
        if (d.contentEditable != 'true') { //it's not REALLY true, checking the boolean value (!== true) always passes, so we can use != 'true' rather than !== true/
            if (regex.test(elements)) {
                event.preventDefault ? event.preventDefault() : event.returnValue = false;
            }
        }
    }
}

*Note that IEs [edit: and Spartan/TechPreview] have a "feature" that makes table-related elements uneditable. If you click one of those and THEN press backspace, it WILL navigate back. If you don't have editable <td>s, this is not an issue.

Josiah
  • 3,008
  • 1
  • 34
  • 45
3

This solution is similar to others that have been posted, but it uses a simple whitelist making it easily customizable to allow the backspace in specified elements just by setting the selector in the .is() function.

I use it in this form to prevent the backspace on pages from navigating back:

$(document).on("keydown", function (e) {
    if (e.which === 8 && !$(e.target).is("input:not([readonly]), textarea")) {
        e.preventDefault();
    }
});
None
  • 5,491
  • 1
  • 40
  • 51
  • 2
    When user uses contenteditable, this would make it disabled. So you might want to add the contenteditable=true in the whitelist – Miguel Jul 24 '13 at 22:57
3

To elaborate slightly on @erikkallen's excellent answer, here is a function that allows all keyboard-based input types, including those introduced in HTML5:

$(document).unbind('keydown').bind('keydown', function (event) {
    var doPrevent = false;
    var INPUTTYPES = [
        "text", "password", "file", "date", "datetime", "datetime-local",
        "month", "week", "time", "email", "number", "range", "search", "tel",
        "url"];
    var TEXTRE = new RegExp("^" + INPUTTYPES.join("|") + "$", "i");
    if (event.keyCode === 8) {
        var d = event.srcElement || event.target;
        if ((d.tagName.toUpperCase() === 'INPUT' && d.type.match(TEXTRE)) ||
             d.tagName.toUpperCase() === 'TEXTAREA') {
            doPrevent = d.readOnly || d.disabled;
        } else {
            doPrevent = true;
        }
    }
    if (doPrevent) {
        event.preventDefault();
    }
});
Community
  • 1
  • 1
Gingi
  • 2,149
  • 1
  • 18
  • 34
  • Thanks, I am using this answer! Have you found any issues with this solutions so far? – Nearpoint Sep 12 '14 at 01:36
  • 1
    I'd recommend moving the INPUTTYPES, TEXTRE declarations out of the function so they don't get recalculated on every keydown event. – thetoolman Nov 24 '14 at 07:00
3

JavaScript - jQuery way:

$(document).on("keydown", function (e) {
    if (e.which === 8 && !$(e.target).is("input, textarea")) {
        e.preventDefault();
    }
});

Javascript - the native way, that works for me:

<script type="text/javascript">

//on backspace down + optional callback
function onBackspace(e, callback){
    var key;
    if(typeof e.keyIdentifier !== "undefined"){
        key = e.keyIdentifier;

    }else if(typeof e.keyCode !== "undefined"){
        key = e.keyCode;
    }
    if (key === 'U+0008' || 
        key === 'Backspace' || 
        key === 8) {
                    if(typeof callback === "function"){
                callback();
            }
            return true;
        }
    return false;
}

//event listener
window.addEventListener('keydown', function (e) {

    switch(e.target.tagName.toLowerCase()){
        case "input":
        case "textarea":
        break;
        case "body":
            onBackspace(e,function(){
                e.preventDefault();
            });

        break;
    }
}, true);
</script>
Vladimir Djuricic
  • 4,323
  • 1
  • 21
  • 22
  • @MichaelPotter It was okay for the use case of mine, long time ago. Please, feel free to contribute by improving/altering my answer. Thx! – Vladimir Djuricic Dec 21 '17 at 09:09
2

I had some problems with the accepted solution and the Select2.js plugin; I was not able to delete characters in the editable box as the delete action was being prevented. This was my solution:

//Prevent backwards navigation when trying to delete disabled text.
$(document).unbind('keydown').bind('keydown', function (event) {

    if (event.keyCode === 8) {

        var doPrevent = false,
            d = event.srcElement || event.target,
            tagName = d.tagName.toUpperCase(),
            type = (d.type ? d.type.toUpperCase() : ""),
            isEditable = d.contentEditable,
            isReadOnly = d.readOnly,
            isDisabled = d.disabled;

        if (( tagName === 'INPUT' && (type === 'TEXT' || type === 'PASSWORD'))
            || tagName === 'PASSWORD'
            || tagName === 'TEXTAREA') {
            doPrevent =  isReadOnly || isDisabled;
        }
        else if(tagName === 'SPAN'){
            doPrevent = !isEditable;
        }
        else {
            doPrevent = true;
        }
    }

    if (doPrevent) {
        event.preventDefault();
    }
});

Select2 creates a Span with an attribute of "contentEditable" which is set to true for the editable combo box in it. I added code to account for the spans tagName and the different attribute. This solved all my problems.

Edit: If you are not using the Select2 combobox plugin for jquery, then this solution may not be needed by you, and the accepted solution might be better.

PrinceTyke
  • 203
  • 1
  • 11
Pytry
  • 6,044
  • 2
  • 37
  • 56
1

Using Dojo toolkit 1.7, this works in IE 8:

require(["dojo/on", "dojo/keys", "dojo/domReady!"],
function(on, keys) {
    on(document.body,"keydown",function(evt){if(evt.keyCode == keys.BACKSPACE)evt.preventDefault()});
});
Chris V
  • 11
  • 1
1

Have you tried the very simple solution of just adding the following attribute to your read only text field:

onkeydown="return false;"

This will keep the browser from going back in history when the Backspace key is pressed in a read only text field. Maybe I am missing your true intent, but seems like this would be the simplest solution to your issue.

B-Dog
  • 11
  • 1
1

A much neater solution -

$(document).on('keydown', function (e) {
    var key = e == null ? event.keyCode : e.keyCode;
    if(key == 8 && $(document.activeElement.is(':not(:input)')))   //select, textarea
      e.preventDefault();
});

Alternately, you could only check if

$(document.activeElement).is('body')
Robin Maben
  • 22,194
  • 16
  • 64
  • 99
1

Pure javascript version, which works in all browsers:

document.onkeydown = function(e) {stopDefaultBackspaceBehaviour(e);}
document.onkeypress = function(e) {stopDefaultBackspaceBehaviour(e);}

function stopDefaultBackspaceBehaviour(event) {
  var event = event || window.event;
  if (event.keyCode == 8) {
    var elements = "HTML, BODY, TABLE, TBODY, TR, TD, DIV";
    var d = event.srcElement || event.target;
    var regex = new RegExp(d.tagName.toUpperCase());
    if (regex.test(elements)) {
      event.preventDefault ? event.preventDefault() : event.returnValue = false;
    }
  }
}

Of course you can use "INPUT, TEXTAREA" and use "if (!regex.test(elements))" then. The first worked fine for me.

1

Performance?

I was worried about performance and made a fiddle: http://jsfiddle.net/felvhage/k2rT6/9/embedded/result/

var stresstest = function(e, method, index){...

I have analyzed the most promising methods i found in this thread. It turns out, they were all very fast and most probably do not cause a problem in terms of "sluggishness" when typing. The slowest Method i looked at was about 125 ms for 10.000 Calls in IE8. Which is 0.0125ms per Stroke.

I found the methods posted by Codenepal and Robin Maben to be fastest ~ 0.001ms (IE8) but beware of the different semantics.

Perhaps this is a relief to someone introducing this kind of functionality to his code.

BenMorel
  • 34,448
  • 50
  • 182
  • 322
felvhage
  • 1,149
  • 8
  • 6
1

Modified erikkallen answer:

$(document).unbind('keydown').bind('keydown', function (event) {

    var doPrevent = false, elem;

    if (event.keyCode === 8) {
        elem = event.srcElement || event.target;
        if( $(elem).is(':input') ) {
            doPrevent = elem.readOnly || elem.disabled;
        } else {
            doPrevent = true;
        }
    }

    if (doPrevent) {
        event.preventDefault();
        return false;
    }
});
Jacek Pietal
  • 1,980
  • 1
  • 18
  • 27
  • 1
    Perfect answer. The solution which I got from others didn't worked in firefox, but this one perfectly worked in all the three(Firefox, IE and crome) without any problem. Thanks Prozi. – Nikhil Dinesh Dec 18 '14 at 09:07
1

This solution worked very well when tested.

I did add some code to handle some input fields not tagged with input, and to integrate in an Oracle PL/SQL application that generates an input form for my job.

My "two cents":

 if (typeof window.event != ''undefined'')
    document.onkeydown = function() {
    //////////// IE //////////////
    var src = event.srcElement;
    var tag = src.tagName.toUpperCase();
    if (event.srcElement.tagName.toUpperCase() != "INPUT"
        && event.srcElement.tagName.toUpperCase() != "TEXTAREA"
        || src.readOnly || src.disabled 
        )
        return (event.keyCode != 8);
    if(src.type) {
       var type = ("" + src.type).toUpperCase();
       return type != "CHECKBOX" && type != "RADIO" && type != "BUTTON";
       }
   }
else
   document.onkeypress = function(e) {
   //////////// FireFox 
   var src = e.target;
   var tag = src.tagName.toUpperCase();
   if ( src.nodeName.toUpperCase() != "INPUT" && tag != "TEXTAREA"
      || src.readOnly || src.disabled )
      return (e.keyCode != 8);
    if(src.type) {
      var type = ("" + src.type).toUpperCase();
      return type != "CHECKBOX" && type != "RADIO" && type != "BUTTON";
      }                              
   }
1

I created a NPM project with a clean version of the currently accepted (of erikkallen)

https://github.com/slorber/backspace-disabler

It uses basically the same principles but:

  • No dependency
  • Support for contenteditable
  • More readable / maintainable code base
  • Will be supported as it will be used in production by my company
  • MIT license

var Backspace = 8;

// See http://stackoverflow.com/questions/12949590/how-to-detach-event-in-ie-6-7-8-9-using-javascript
function addHandler(element, type, handler) {
    if (element.addEventListener) {
        element.addEventListener(type, handler, false);
    } else if (element.attachEvent) {
        element.attachEvent("on" + type, handler);
    } else {
        element["on" + type] = handler;
    }
}
function removeHandler(element, type, handler) {
    if (element.removeEventListener) {
        element.removeEventListener(type, handler, false);
    } else if (element.detachEvent) {
        element.detachEvent("on" + type, handler);
    } else {
        element["on" + type] = null;
    }
}




// Test wether or not the given node is an active contenteditable,
// or is inside an active contenteditable
function isInActiveContentEditable(node) {
    while (node) {
        if ( node.getAttribute && node.getAttribute("contenteditable") === "true" ) {
            return true;
        }
        node = node.parentNode;
    }
    return false;
}



var ValidInputTypes = ['TEXT','PASSWORD','FILE','EMAIL','SEARCH','DATE'];

function isActiveFormItem(node) {
    var tagName = node.tagName.toUpperCase();
    var isInput = ( tagName === "INPUT" && ValidInputTypes.indexOf(node.type.toUpperCase()) >= 0 );
    var isTextarea = ( tagName === "TEXTAREA" );
    if ( isInput || isTextarea ) {
        var isDisabled = node.readOnly || node.disabled;
        return !isDisabled;
    }
    else if ( isInActiveContentEditable(node) ) {
        return true;
    }
    else {
        return false;
    }
}


// See http://stackoverflow.com/questions/1495219/how-can-i-prevent-the-backspace-key-from-navigating-back
function disabler(event) {
    if (event.keyCode === Backspace) {
        var node = event.srcElement || event.target;
        // We don't want to disable the ability to delete content in form inputs and contenteditables
        if ( isActiveFormItem(node) ) {
            // Do nothing
        }
        // But in any other cases we prevent the default behavior that triggers a browser backward navigation
        else {
            event.preventDefault();
        }
    }
}


/**
 * By default the browser issues a back nav when the focus is not on a form input / textarea
 * But users often press back without focus, and they loose all their form data :(
 *
 * Use this if you want the backspace to never trigger a browser back
 */
exports.disable = function(el) {
    addHandler(el || document,"keydown",disabler);
};

/**
 * Reenable the browser backs
 */
exports.enable = function(el) {
    removeHandler(el || document,"keydown",disabler);
};
Sebastien Lorber
  • 89,644
  • 67
  • 288
  • 419
1

Here is my rewrite of the top-voted answer. I tried to check element.value!==undefined (since some elements like may have no html attribute but may have a javascript value property somewhere on the prototype chain), however that didn't work very well and had lots of edge cases. There doesn't seem to be a good way to future-proof this, so a whitelist seems the best option.

This registers the element at the end of the event bubble phase, so if you want to handle Backspace in any custom way, you can do so in other handlers.

This also checks instanceof HTMLTextAreElement since one could theoretically have a web component which inherits from that.

This does not check contentEditable (combine with other answers).

https://jsfiddle.net/af2cfjc5/15/

var _INPUTTYPE_WHITELIST = ['text', 'password', 'search', 'email', 'number', 'date'];

function backspaceWouldBeOkay(elem) {
    // returns true if backspace is captured by the element
    var isFrozen = elem.readOnly || elem.disabled;
    if (isFrozen) // a frozen field has no default which would shadow the shitty one
        return false;
    else {
        var tagName = elem.tagName.toLowerCase();
        if (elem instanceof HTMLTextAreaElement) // allow textareas
            return true;
        if (tagName=='input') { // allow only whitelisted input types
            var inputType = elem.type.toLowerCase();
            if (_INPUTTYPE_WHITELIST.includes(inputType))
                return true;
        }   
        return false; // everything else is bad
    }
}

document.body.addEventListener('keydown', ev => {
    if (ev.keyCode==8 && !backspaceWouldBeOkay(ev.target)) {
        //console.log('preventing backspace navigation');
        ev.preventDefault();
    }
}, true); // end of event bubble phase
ninjagecko
  • 88,546
  • 24
  • 137
  • 145
1

This code solves the problem in all browsers:

onKeydown:function(e)
{
    if (e.keyCode == 8) 
    {
      var d = e.srcElement || e.target;
      if (!((d.tagName.toUpperCase() == 'BODY') || (d.tagName.toUpperCase() == 'HTML'))) 
      {
         doPrevent = false;
      }
       else
      {
         doPrevent = true;
      }
    }
    else
    {
       doPrevent = false;
    }
      if (doPrevent)
      {
         e.preventDefault();
       }

  }
Haseeb Akhtar
  • 1,233
  • 3
  • 16
  • 32
1
    document.onkeydown = function (e) {    
        e.stopPropagation();
        if ((e.keyCode==8  ||  e.keyCode==13) &&
            (e.target.tagName != "TEXTAREA") && 
            (e.target.tagName != "INPUT")) { 
            return false;
        }
    };
elico3000
  • 27
  • 1
  • 2
    You shouldn't use return false. e.preventDefault is recommended. Also you are stopping propagation of the event for every key and not just the backspace. Finally, keyCode 13 is enter and the question was about preventing back navigation with backspace, but this would prevent enter from submitting the form or performing other actions. – None Dec 07 '12 at 03:36
1

Simplest way to prevent navigation on pressing backspace

$(document).keydown(function () {
    if (event.keyCode == 8) {
        if (event.target.nodeName == 'BODY') {
            event.preventDefault();
        }
    }
});
Luke Woodward
  • 63,336
  • 16
  • 89
  • 104
0

I've been using this in my code for some time now. I write online tests for students and ran into the problem when students were pressing backspace during their test and it would take them back to the login screen. Frustrating! It works on FF for sure.

document.onkeypress = Backspace;
function Backspace(event) {
    if (event.keyCode == 8) {
        if (document.activeElement.tagName == "INPUT") {
            return true;
        } else {
            return false;
        }
    }
}
Tan
  • 1
0

Worked for me

<script type="text/javascript">


 if (typeof window.event != 'undefined')
    document.onkeydown = function()
    {
        if (event.srcElement.tagName.toUpperCase() != 'INPUT')
            return (event.keyCode != 8);
    }
else
    document.onkeypress = function(e)
    {
        if (e.target.nodeName.toUpperCase() != 'INPUT')
            return (e.keyCode != 8);
    }

</script>
Pieter de Vries
  • 101
  • 2
  • 13
0

For anyone who is interested, I've put together a jQuery plugin that incorporates thetoolman's (plus @MaffooClock/@cdmckay's comments) and @Vladimir Kornea's ideas above.

Usage:

//# Disable backspace on .disabled/.readOnly fields for the whole document
$(document).disableBackspaceNavigation();

//# Disable backspace on .disabled/.readOnly fields under FORMs
$('FORM').disableBackspaceNavigation();

//# Disable backspace on .disabled/.readOnly fields under #myForm
$('#myForm').disableBackspaceNavigation();

//# Disable backspace on .disabled/.readOnly fields for the whole document with confirmation
$(document).disableBackspaceNavigation(true);

//# Disable backspace on .disabled/.readOnly fields for the whole document with all options
$(document).disableBackspaceNavigation({
    confirm: true,
    confirmString: "Are you sure you want to navigate away from this page?",
    excludeSelector: "input, select, textarea, [contenteditable='true']",
    includeSelector: ":checkbox, :radio, :submit"
});

Plugin:

//# Disables backspace initiated navigation, optionally with a confirm dialog
//#     From: https://stackoverflow.com/questions/1495219/how-can-i-prevent-the-backspace-key-from-navigating-back
$.fn.disableBackspaceNavigation = function (vOptions) {
    var bBackspaceWasPressed = false,
        o = $.extend({
            confirm: (vOptions === true),   //# If the caller passed in `true` rather than an Object, default .confirm accordingly,
            confirmString: "Are you sure you want to leave this page?",
            excludeSelector: "input, select, textarea, [contenteditable='true']",
            includeSelector: ":checkbox, :radio, :submit"
        }, vOptions)
    ;

    //# If we are supposed to use the bConfirmDialog, hook the beforeunload event
    if (o.confirm) {
        $(window).on('beforeunload', function () {
            if (bBackspaceWasPressed) {
                bBackspaceWasPressed = false;
                return o.confirmString;
            }
        });
    }

    //# Traverse the passed elements, then return them to the caller (enables chainability)
    return this.each(function () {
        //# Disable backspace on disabled/readonly fields
        $(this).bind("keydown keypress", function (e) {
            var $target = $(e.target /*|| e.srcElement*/);

            //# If the backspace was pressed
            if (e.which === 8 /*|| e.keyCode === 8*/) {
                bBackspaceWasPressed = true;

                //# If we are not using the bConfirmDialog and this is not a typeable input (or a non-typeable input, or is .disabled or is .readOnly), .preventDefault
                if (!o.confirm && (
                    !$target.is(o.excludeSelector) ||
                    $target.is(o.includeSelector) ||
                    e.target.disabled ||
                    e.target.readOnly
                )) {
                    e.preventDefault();
                }
            }
        });
    });
}; //# $.fn.disableBackspaceNavigation
Community
  • 1
  • 1
Campbeln
  • 2,880
  • 3
  • 33
  • 33
0

All of the answers given so far focus on scripting the fix into the web page, but what if I simply want the feature for myself, without affecting other users?

In this case a solution for the browser itself is to be preferred:
- Firefox on Linux "unmapped" the backspace behavior since 2006 so it's not affected; (at any rate, it was simply set to scroll up before then)
- Chrome has just announced that it will do the same from now on; (http://forums.theregister.co.uk/forum/1/2016/05/20/chrome_deletes_backspace/)
- Firefox on Windows can be set to ignore backspace by going into about:config and changing the backspace_action setting to 2; (http://kb.mozillazine.org/Browser.backspace_action)
- Safari ?!

Paolo
  • 61
  • 8
0

Another method using jquery

    <script type="text/javascript">

    //set this variable according to the need within the page
    var BACKSPACE_NAV_DISABLED = true;

    function fnPreventBackspace(event){if (BACKSPACE_NAV_DISABLED && event.keyCode == 8) {return false;}}
    function fnPreventBackspacePropagation(event){if(BACKSPACE_NAV_DISABLED && event.keyCode == 8){event.stopPropagation();}return true;}

    $(document).ready(function(){ 
        if(BACKSPACE_NAV_DISABLED){
            //for IE use keydown, for Mozilla keypress  
            //as described in scr: http://www.codeproject.com/KB/scripting/PreventDropdownBackSpace.aspx
            $(document).keypress(fnPreventBackspace);
            $(document).keydown(fnPreventBackspace);

            //Allow Backspace is the following controls 
            var jCtrl = null;
            jCtrl = $('input[type="text"]');
            jCtrl.keypress(fnPreventBackspacePropagation);
            jCtrl.keydown(fnPreventBackspacePropagation);

            jCtrl = $('input[type="password"]');
            jCtrl.keypress(fnPreventBackspacePropagation);
            jCtrl.keydown(fnPreventBackspacePropagation);

            jCtrl = $('textarea');
            jCtrl.keypress(fnPreventBackspacePropagation);
            jCtrl.keydown(fnPreventBackspacePropagation);

            //disable backspace for readonly and disabled
            jCtrl = $('input[type="text"][readonly="readonly"]')
            jCtrl.keypress(fnPreventBackspace);
            jCtrl.keydown(fnPreventBackspace);

            jCtrl = $('input[type="text"][disabled="disabled"]')
            jCtrl.keypress(fnPreventBackspace);
            jCtrl.keydown(fnPreventBackspace);
        }
    }); 

    </script>
CodeNepal
  • 732
  • 7
  • 11
0

Sitepoint: Disable back for Javascript

event.stopPropagation() and event.preventDefault() do nothing in IE. I had to send return event.keyCode == 11 (I just picked something) instead of just saying "if not = 8, run the event" to make it work, though. event.returnValue = false also works.

John Conde
  • 217,595
  • 99
  • 455
  • 496
Tom
  • 69
  • 1