Twitter bootstrap modal input field focus
Asked Answered
F

9

54

I have the following modal form from example:

<!-- Button to trigger modal -->
<a href="#myModal" role="button" class="btn" data-toggle="modal">Launch demo modal</a>

<!-- Modal -->
<div id="myModal" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
  <div class="modal-header">
    <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
    <h3 id="myModalLabel">Modal header</h3>
  </div>
  <div class="modal-body">
    Enter something: <input type="text" id="myInput">
  </div>
  <div class="modal-footer">
    <button class="btn" data-dismiss="modal" aria-hidden="true">Close</button>
    <button class="btn btn-primary">Save changes</button>
  </div>
</div>

I want my input field to be focused after modal is shown.
I've tryed both autofocus and setting field focus on $('modal').shown() event. It kinda focuses field (I have another event which shows label when field is focused) but in fact field is not focused and I have to press TAB to focus it again. I also tried something like this:

$(".modal").on('shown', function() {
    $(this).find("[autofocus]:first").focus();
});

and setting autofocus:"autofocus" attribute for my field. It gave same effect.
Everything I tried works for when modal is just a usual div, it gets focus on page load. But when modal is triggered by button - nothing works (sure I change logic also, when modal is just a usual div I can focus it onload, when I trigger by button I take it into account and try to solve it accordingly).

What I want is just field to be focused after modal is loaded, so that it has blinking cursor and user can just start typing.

Only thing that worked is changing bootstrap.js itself, I've put $("#myInput").focus() somewhere inside bootstrap.js modal section but well I forgot where it was, and second - I think it's not good to change bootstrap.js API, there must be easier and more elegant solution. Advice me please, thanks xD

UPDATE:
First of all, thanks for your help! Thanks to you I figured out that problem I had is Rails problem.

Here is what I did:
1). rails generate controller home index
2). app/views/home/index.html and app/assets/javascript/something.js are like in this jsFiddle provided by robertklep: http://jsfiddle.net/JCaFp/
4). jquery-1.9.1.js and bootstrap.js are in app/assets/javascript/ (both are fresh from website, nothing changed)
5). app/views/layouts/application.html.erb - I guess this file is the key of our solution:

<!DOCTYPE html>
<html>
<head>
  <title>Udc</title>
  <%= stylesheet_link_tag    "application", :media => "all" %>
  <%= javascript_include_tag "application" %>
  <%= csrf_meta_tags %>
</head>
<body>

<%= yield %>

</body>
</html>

Still doesn't work. All js files get included, but when I open my modal in browser - input get focus for a moment and gets unfocused again.

I've also tried this:

  <%= javascript_include_tag "jquery" %>
  <%= javascript_include_tag "bootstrap" %>
  <%= javascript_include_tag "somehow" %>

Still same stuff.
Suggestions? :)

UPDATE:

Solved it!

After changing my somehow.js to

$(document).ready(function() {
    $(".modal").on('shown', function() {
        $(this).find("[autofocus]:first").focus();
    });
});

and application.html.erb stylesheet to:

  <%= javascript_include_tag "jquery" %>
  <%= javascript_include_tag "bootstrap" %>
  <%= javascript_include_tag "somehow" %>

it works as expected. Thanks again!

Frenchify answered 18/3, 2013 at 10:42 Comment(2)
Your code inside the shown handler works just fine for me (provided you actually set the autofocus attribute, otherwise the selector won't find it): demo hereAntibes
robert, can you please add your comment as an answer? I will mark it as the right one :)Frenchify
H
82

I think the shown event name changed in Bootstrap 3, as explained in this post.

As @MrDBA notes, in Bootstrap 3 the event name is changed to shown.bs.modal.

So, for Bootstrap 3 use:

$('#myModal').on('shown.bs.modal', function () {
    $('#myInput').focus();
})
Hindmost answered 17/12, 2013 at 8:44 Comment(1)
This really is the definitive answer, because even if you set the field to autofocus in the HTML control then the control will get focus for a brief moment as the modal dialog appears and then lose focus again. Thanks.Gupta
T
41

For a general solution that doesn't require specific code for each dialog, you can use this:

$('.modal').on('shown.bs.modal', function () {
  $(this).find('input:text:visible:first').focus();
})
Thetes answered 9/5, 2014 at 18:26 Comment(6)
I still wonder why bootstrap is specifically overriding the focus, and how that can be controlled.Thetes
Had to drop the :text for may case (password field), but otherwise works nicely.Sulky
You can remove the following line (it's redundant in this example): lastfocus = $(this);Shaquana
Awesome, thanks. I changed $('.modal').on to $(document).on for my use case - a single page app with dynamically generated modals.Kris
For an even more general solution, the text inside the selector could be removed, so that any kind of input will be detected.Incarnation
@Thetes how did you manage to keep the focus in the modal when you reach the last element in your modal? because with solution it works as long as you don't reach the last element and when you do, the focus is back to the background.Itagaki
C
13

Try removing tabindex="-1" and it works nice.

So change this:

<div class="modal fade" id="modalID" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">

To this:

<div class="modal fade" id="modalID" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
Communalize answered 12/2, 2015 at 6:49 Comment(3)
This whole ordeal with auto focusing an element has been driving me nuts until I came across this answer. Removing the tabindex="-1" from my dialog fixed the issue for me!Inoffensive
Oh my, this solves the problem too. Deserves more upvotes! But, there probably is a reason why tabindex is -1. Wonder if we break something by removing this.Hurtado
@MārtiņšBriedis Removing tabindex breaks the functionality to close the modal with the Esc key.Towboat
O
8

If you have problems with "shown.bs.modal", just set a timeout.

setTimeout(function() {
$('#myInput').focus();
}, 500);
Overtone answered 28/4, 2014 at 1:30 Comment(0)
D
7

Just changing $(this).find("[autofocus]:first").focus(); to $(this).find("#myInput").focus(); made it work for me. If you have changed the Bootstrap API and want to undo that change, you can always just re-download and replace the file.

Dumbbell answered 18/3, 2013 at 10:57 Comment(0)
P
6

I removed tabindex="-1" and it works so nice.

My HTML code before changes:

<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">

My HTML code after changes:

<div class="modal fade" id="myModal" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">

My Input code:

<input id="tblModalNombreConductor" type="text" maxlength="50" placeholder="Ej: Armando Casas" autofocus/>

And I have no configurations in my Javascript code.

Pinky answered 10/3, 2015 at 14:20 Comment(1)
This works only once for me. Closing and re-opening the modal doesn't focus.Towboat
A
3

I think the updated answer is pretty clever. Here is another way to solve it.

Bootstrap 3.2's js file includes a script to manage focus during and after the modal's fade transition. This interferes with any jQuery, javascript or rails+HTML5 focusing on a form field in the modal - bootstrap removes your focus after the modal loads.

To remove bootstrap's ability to override your focus, comment out this line in the Modal script area:

transition ?
    that.$element.find('.modal-dialog') // wait for modal to slide in
      .one($.support.transition.end, function () {
        // that.$element.focus().trigger(e)
        // the line above is stealing your focus after modal loads!
      })
      .emulateTransitionEnd(300) :
    that.$element.focus().trigger(e) 

Now your field should be able to have focus in any modal form.

Alleged answered 6/12, 2013 at 23:33 Comment(1)
I am seeing this also. I'm wondering what that line is attempting to accomplish. Looks as if it's trying to set focus on the modal. Is there a way to take advantage of what bootstrap is doing here rather than monkey-patching the behavior?Thetes
A
1

You can do: e.g

<%= f.text_field :first_name, class: "form-control", placeholder: "Enter first name", autofocus: true%>

just add this: autofocus: true

Abortion answered 2/3, 2015 at 17:58 Comment(0)
W
0

You can also try

$('#the-modal').on('shown.bs.modal', function(e) {
    $('#the-input').focus();
});
Wrongly answered 17/6, 2016 at 9:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.