34

I want my (ExtJS) toolbar buttons not to grab the focus on the web page when they are clicked, but to do their "thing" while leaving the focus unchanged by the click. How do I do that?

Bob Stein
  • 16,271
  • 10
  • 88
  • 101
Mike Peat
  • 445
  • 1
  • 6
  • 14
  • I think you may change the accepted answer, and select the most upvoted one, this will be of great help to people reading this helpful question. – Hakan Fıstık Apr 30 '19 at 05:54

11 Answers11

54

Cancelling the default behavior of onmousedown prevents an element from getting the focus:

// Prevent capturing focus by the button.
$('button').on('mousedown', 
    /** @param {!jQuery.Event} event */ 
    function(event) {
        event.preventDefault();
    }
);
Bob Stein
  • 16,271
  • 10
  • 88
  • 101
real4x
  • 1,433
  • 12
  • 11
6

document.activeElement stores the currently focussed element.

So on your toolbar, you can add a "mousedown" handler to this function :

function preventFocus() {
  var ae = document.activeElement;
  setTimeout(function() { ae.focus() }, 1);
}

Try this example :

<html>
<head>
<script>
function preventFocus() {
  var ae = document.activeElement;
    setTimeout(function() { ae.focus() }, 1);
}
</script>
</head>
<body>
<input type="text"/>
<input type="button" onmousedown="preventFocus()" onclick="alert('clicked')" value="Toolbar" />
</body>
</html>
Alsciende
  • 26,583
  • 9
  • 51
  • 67
  • 1
    document.activeElement is part of HTML5. Only Firefox2 and Safari don't support it, though the last nightly builds of Safari are reported to support it. – Alsciende Jun 12 '09 at 12:20
  • Since you are using onmousedown, you can just use preventDefault and not bother with storing the currently active element since it will never get focused. However, you might want to give the button some highlight that you undo with a timer some 500ms or so later in order to show that the button was clicked. – Evan Langlois Jan 18 '17 at 04:46
5

This usually does the trick for me:

<button 
  tabindex="-1"
  onclick="javascript:console.log('do your thing')"
>My Button</button>

From https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/tabindex:

A negative value (usually tabindex="-1") means that the element should be focusable, but should not be reachable via sequential keyboard navigation. It's mostly useful to create accessible widgets with JavaScript.

Lukas Bünger
  • 4,257
  • 2
  • 30
  • 26
4

The top-voted answer is technically correct, but depends on jQuery...

Here's a simpler example:

<span onclick="document.execCommand('bold', false);" onmousedown="event.preventDefault();"></span>
afloesch
  • 91
  • 3
4

I don't think there's an easy way to do what you want to do because it's the browser's default behaviour.

You could of course blur() the button as soon as it is clicked, but that would simply unselect everything. To have the previously active object regain focus, you'd have to create a "memory" of sorts by adding a blur handler for every element to keep track of which element had/lost focus last (store the id of the element in a global and update it when an element loses focus).

Alan Plum
  • 10,814
  • 4
  • 40
  • 57
2

My solution is to replace <button /> with <div /> and style it as a button. Looks like Div doesn't take a focus on it when you click it.

jamland
  • 931
  • 15
  • 23
1

I would attach one blur event listener to all fields. This listener should save the field, that lost the focus, in a global variable.

Then all the toolbar button should get one focus event listener. This listener should focus the field, that was saved as described above.

This code should work, although it didn't test it

Jochen
  • 66
  • 4
1
<script>
    function focusor(){
        document.getElementById('focus').focus;
    }
    document.onkeydown = focusor;
    document.onclick = focusor;
</script>
<div style="width: 0px; height: 0px; overflow: hiddden;">
    <button id="focus"></button>
</div>

What I have found, is you will have to make a dummy element, I found buttons to work best in this situation. put the button in a div and make the div 0px.

[do not make the div display none, some browsers will just ignore it]

Basically any click or button presses, it will focus on this dummy button. I had a project very similar and whenever they pressed the down key it selected the first button on the page, this just focuses on the button over and over again.

Sort of jacked up, but it works.

Dillon Burnett
  • 473
  • 4
  • 11
1

Because the toolbar buttons are just styled ordinary HTML button elements then this is an actual browser behavior, and you should think twice before changing it. But nevertheless...

You should be able to prevent the botton from receiving focus by just returning false from its onclick handler.

Rene Saarsoo
  • 13,580
  • 8
  • 57
  • 85
  • Thanks Rene I thought that was the right approach, but it didn't seem to work when I tried it. ATM I have implemented a nasty solution where on each Form I set defaults: { onBlur: fieldExit } where fieldExit puts the calling object into a lastField variable, then at the end of the buttons' handler (they all use the same one) I do lastField.focus(). This works for text fields, but oddly not for checkboxes (I have not tested others yet). – Mike Peat Jun 11 '09 at 23:02
  • you can prevent the button *keeping* focus, but you can't return focus to the previous element without keeping track of such – annakata Jun 12 '09 at 11:00
  • When on click is firing it's too late to cancel the focus. As I stated above preventing of the default behavior should be done in onmousedown. It will not prevent "onclick" but it will prevent focus change. At least in the Webkit browsers. – real4x Jun 20 '15 at 06:27
1

Maybe you should try to use stateful and state change properties for form fields or whatever to get focus back?

Thevs
  • 3,189
  • 2
  • 20
  • 32
-3

All these answers are wack. Here's a very excellent trick that only uses CSS

<button type="submit" disabled>
  <span>Submit</span> <!-- the <span> is the secret -->
</button>

Now in your css:

button[disabled] > * {
  pointer-events: none;
}

The trick is the inner span has to be used, otherwise the button will still steal focus away from inputs.

Tallboy
  • 12,847
  • 13
  • 82
  • 173