6

I am trying to design a form such that if it has a certain class, the user should not be able to interact with any of the inputs. For various reasons, I would like to avoid using the "disabled" attribute. I am trying to prevent the default on the focus event and it is not working. I tested this in recent versions of Firefox, Chrome, and Android. I tried various combinations of events, such as "click change touchstart focus focusin". I tried puting "return false;" in the handler. Does anyone know why this is happening and how to make it work?

<!DOCTYPE html>
<html><head>
<title>input test</title>
</head>
<body>
<form class="disabled">
  <input type="text">
</form>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"></script>
<script type="text/javascript">
$(".disabled :input").bind("focus", function(e) {
  e.preventDefault();
});
</script>
</body></html>

You can see an example at http://jsfiddle.net/54Xka/

EDIT: This will be on a site intended mostly for mobile browsers. I am planning to disable the inputs when a modal dialog is showing. The modal dialog is implemented using my own code. It is something very simple that shows and hides a div.

EDIT 2: This is what I have now:

$(".disabled :input").live({
  focus: function() {
    $(this).blur();
  },
  change: function(e) {
    e.preventDefault();
  }
});

It has some minor aesthetic issues but it works. When I have more time, I may try jfriend00's idea with the transparent gif, or something similar to what the jQuery UI dialog widget does, or maybe actually using the jQuery UI dialog widget to implement the dialog.

Elias Zamaria
  • 96,623
  • 33
  • 114
  • 148

3 Answers3

7

For text fields, the best thing to do is to set them to read only. This still allows tabbing and copying, but not modification.

<input type="text" readonly="readonly" value="Can't change me">

If you also want to stop tabbing, then a proper functioning web page supports keyboard navigation among the objects on the page intended for keyboard access. That means that any option that just simply tries to block the focus will interrupt any attempt to navigate the web page via keyboard. As such, it's best to block tabbing between items by telling the browser that this object is not intended as a tab stop and it will happily just skip over it when the tab key is pressed. You can do so by settings tabIndex to -1 on the object. Keyboard navigation will never stop on it then, but will otherwise work as intended.

<input type="text" readonly="readonly" tabIndex="-1" value="Can't change me or tab to me">

If you're using different types of objects than text fields, then please be more specific about what types of objects. You should pursue the HTML attributes that support your intended behavior before resorting to scripts that mess with the expected functioning of the web page. It may also make sense to use something other than a usereditable tag to just display data (like a div) too if you don't intend for the user to be able to interact with it.

You can see examples of readonly and tabIndex fields here: http://jsfiddle.net/jfriend00/9wWkQ/

Now, it sounds like we have moving specifications. Now you're saying you don't even want them to be able to select text. That can be done even in a plain div that isn't editable. If you want to block all user access including even selecting of the text of individual fields, then you will have to resort to something like putting a blank transparent gif image over the top of the area of your form. That will block all mouse interaction with the fields and combined with readonly and tabIndex should block all keyboard access too.

jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • Thanks. I didn't think of the tab key. The readonly attribute is not an option since I am trying to prevent the user from interacting with the form. The tabindex is something I may consider. – Elias Zamaria Jul 18 '11 at 23:37
  • Actually, the tabindex attribute by itself is not an option. The user can still select the input by touching it. – Elias Zamaria Jul 18 '11 at 23:38
  • I add one more option to my answer above if you really want to prevent ALL interaction. The readonly attribute prevents all changing of the items. Why is that not desirable and part of a solution to your problem? – jfriend00 Jul 18 '11 at 23:42
  • I am trying to implement a modal dialog, which prevents elements off of the dialog from being focused. – Elias Zamaria Jul 18 '11 at 23:57
  • 2
    Then, the standard way of doing that is to place a transparent gif image over the whole page (you can scale a 1x1 image to cover the page) and put your dialog on top of it. We could have solved this a ton faster if you had said this in your question. – jfriend00 Jul 19 '11 at 00:04
5

you may use

this.blur();

...instead.

Dr.Molle
  • 116,463
  • 16
  • 195
  • 201
  • 1
    I'm upvoting your answer because it's helpful. However, it has some small aesthetic problems. On the iPhone, if I click an input, the on-screen keyboard appears for a fraction of a second. It's not horrible but it is somewhat distracting. On several Android devices, if I try it on a password input, it will sometimes look like it is focused, but not let me type anything. On my Droid 2, which has a physical keyboard, pressing keys will show the character I typed for a fraction of a second, then change back. I'm hoping for a better solution but I may accept this if I don't find a better solution. – Elias Zamaria Jul 18 '11 at 23:13
  • Unfortunately the focus-event is not cancelable. Can you explain why you woukdn't like to use the disabled-attribute? – Dr.Molle Jul 18 '11 at 23:46
  • I am trying to avoid the disabled attribute because it may be cumbersome. When I show the dialog, I will have to disable all the inputs. When the dialog is hidden, the inputs' disabled attributes will have to be reset to their original values (since some of the inputs may have been disabled for other reasons). Therefore, I will need a way to remember the values of the disabled attributes. It is something I can do, but it may take more code. I am wondering if there is a simpler and more elegant way. – Elias Zamaria Jul 19 '11 at 18:17
  • 1
    I'm not sure if it is an option to you, but the simpliest approach should be to hide the complete form. Hidden elements can not be focused. – Dr.Molle Jul 19 '11 at 18:28
4

You cannot prevent default, but you can immediately restore focus to the previously focused element (which is almost the same as if the element did not receive focus). This is easily doable as relatedTarget property of FocusEvent contains reference to the previously focused element.

element.addEventListener('focus', (e) => {
  if (e.relatedTarget) {
    e.relatedTarget.focus();
  }
});

Maciej Krawczyk
  • 14,825
  • 5
  • 55
  • 67
  • Your solution actually helped me to prevent a dropdown to grab the focus outside the textarea. The dropdown was intended to pick a text, among many options, to insert where the cursor was laying in the textarea. Thanks – Diego D Mar 15 '22 at 16:39
  • I don't think that's a good solution. Rather than simply making element not focusable (and thus make it be skipped in the focus order), this solution prevents the user from focusing this element OR any element after this one – Max Patiiuk Aug 18 '23 at 17:42
  • @Max it depends on what you are trying to do. Making the element unfocusable will bring focus to the parent element that is unfocusable, but I wanted to specifically ignore focus effects when a button was clicked and restore focus to whatever element that had it before the click. Yes, I forgot to add that the element should have tabIndex="-1" as well because otherwise it will break keyboard navigation. – Maciej Krawczyk Aug 19 '23 at 07:25