-
Notifications
You must be signed in to change notification settings - Fork 6.7k
$modal does not stop tabbing on the background #738
Comments
Yeh, this is a valid point. We should fix this. |
I can see the last Bootstrap version modal dialog was setting the tabindex = -1 to prevent this. But I tried it on the markup it does not fix it. |
Well this is going to be a tough one. I played with it a bit today and here's what I've found: The tab-index trick Bootstrap is using is quite dependent on careful layout of the page (in fact, all items that can be tabbed to on a page must also have a tab-index). The only other way to fix this is to bind to the tab keypress event, determine if the |
👍 I would really like to see this one fixed soon! @hall5714 - i wonder if there is a way to wrap it around to the first element on the modal if the target isn't a child of the modal. having it halt on the Cancel button or whatever would be sub-optimal. How long to get this on the roadmap? Shall I have a go and submit a pull? |
They have a workaround for this problem in Bootbox (http://bootboxjs.com/#examples), which also uses Bootstrap dialogs, except they somehow managed to disable tabbing on the page behind the dialog. Can we maybe look how they got around this issue? |
I also did my own workaround for this problem, but by completely overriding the tab behaviour and taking over from the browser (manually moving focus between fields), and only when a dialog was open. I don't think this is a good solution however, and think it would be better to see how they got around this problem in Bootbox.js first. |
I think the fix is in bootstrap itself, as I don't see any tab handling code in bootbox.js. I would fork this and work on a fix for this, but I'm having GIT difficulties. Seems I already forked master and made some changes for another defect that were submitted as a pull but weren't needed. Now when I fork master it just goes back to my old fork and it has junk that I don't want. I tried reverting changes, but I just don't know if my current source really reflects the bootstrap master. How can do a completely clean fork? Can I delete the old one? It's not jumping out at me. |
figured out how to delete my old repo and have reforked it. Will take a go at this issue. |
yup... bootstrap 3 has this to keep the focus in the modal: Modal.prototype.enforceFocus = function () {
$(document)
.off('focusin.bs.modal') // guard against infinite focus loop
.on('focusin.bs.modal', $.proxy(function (e) {
if (this.$element[0] !== e.target && !this.$element.has(e.target).length) {
this.$element.focus()
}
}, this))
} unfortunately, this is using a lot of heavy jquery, like $.proxy to provide context, event namespacing, the .has() function. Let me see what I can do with @hall5714's suggestion above. |
I have a branch commit in my repo that implements a fix for this issue (jmwolfe@759cddb). I would appreciate feedback before bothering with a pull request. This uses the same basic approach that bootstrap 3's modals use (without bootstrap of course). I do assume you want to move your focus after the last item to the first INPUT or TEXTAREA tag. We can discuss that as needed. |
@jmwolfe left some comments in jmwolfe@759cddb |
I have incorporated Pawel's feedback in the most recent revision in my tab-fix branch, here: https://github.com/jmwolfe/bootstrap/compare/modal_bg_tab_disable. Hope we can get close and I can propose a PR. |
Hey, I was wondering if there is any eta on when this will be fixed. |
Hi @jmwolfe, any feedback on a PR? |
+1 on having this fixed. @jmwolfe: Have actually propsed a PR yet? |
+1 |
Its been 8 months since that fork was made, can it be assumed that the effort to get them PR'ed into the main repo is pretty much dead? |
Perhaps someone else (you) can create a PR containing those changes and credit the original contributors who weren't able to make a PR. |
Hey Guys... Sorry I have been delinquent with the PR! I forked this a while back. I imagine this code base has changed quite a bit since September. Suggestions on the fastest way to get a useful PR out for you guys? Should I do a new fork from some version (please specify) and re-implement the changes? What about Boostrap 3? I think I did start backing off when I heard 3.0 was coming.. I was not sure a fix based on an earlier version would be useful. Unfortunately, I took on a more demanding role at my workplace and my time is more limited. I'll try to get a PR together in the next few weeks. If I could get a bit of summary from someone who's had time to follow all the goings on so that the PR would be acceptable, that would be a great contribution. |
@jmwolfe , no worries, I think that happens to every one of us (or most of us anyway 😄 ), I think the fastest way would be to create your fix on top the current master branch. We're unlikely to maintain older versions of UI Bootstrap due to our lack of resources. Thank you! 👍 |
Update to the below... I just did as I suggested and wiped the old repo. Unfortunately I was not smart enough to have the current branch set to mine before I did so, so I lost those changes. :/ Fortunately, I had the changes in my other project (that i need this functionality for) so I got the mods and now have a branch off my master fork working well. OK. I have my old repository that was forked from angular-ui/boostrap in I guess I could move the local cloned files elsewhere for reference and Tips? On Thu, Jun 12, 2014 at 11:40 PM, Chris Chua [email protected]
|
OK! I think I have what appears to be a fix,. However.... in writing the automated tests, I'm having a very difficult time simulating tab presses... looks like FF has security issues that prevent "full user input emulation". In Chrome, the triggerkeyDown() method supplied in the existing modal spec is not changing the activeElement on the document, which is I think the most straightforward way to test whether the focus changed. However, I'm about ready to abandon activeElement probing and try another approach to validate focus... but honestly, after a few hours of googling, we may have to forgo automated testing of this part unless someone has some working examples. Also, not sure I can do this, but do we need to exclude the move to the address bar when tabbing? that happens at this point in my solution. Tx |
@jmwolfe - its normal with a WCAG compliant accessible modal that focus is entirely contained within the modal - both tab and shift-tab, no moving to the address bar. |
Has AngularJS or Angular-UI made any assertions of being WCAG compliant? I On Sat, Jul 5, 2014 at 8:00 PM, Ian Kelly [email protected] wrote:
|
tabindex is doing interesting things. All works well with no tabindex setting on any element... just tabs through all valid elements in the order of creation (I guess). If you add tabindex ="-1" it will take them out of the tab sequence. Which is good. But if you use any other value of tabindex, the focus will leave the modal unexpectedly. I can capture that and put it back into the first element in the modal.. but not sure that's what we want. But even stranger, the browser is having a hard time honoring the tabindex order... not sure if that's because i'm using the demo page and there are so many other elements or what. E.g., I have five tabbable elements, and I put tabindex attrs on the last two. When I open the modal and hit tab, the focus goes to the first of the five elements, not the fourth as I would have expected. Any ideas why? |
Sorry all, it appears the PR was considered substandard (it re-implemented tabbing rather than using a bettter approach of catching focusin events). So I am back to the drawing board. |
Have we considered the following?
I can POC this and show that this can work with jQuery. What I'm not too sure of is whether there's a jQlite / angular way of getting all tabbable elements which is required for an approach like this to work. Thoughts? *** Slight update See WAI-ARIA 1.0 Authoring Practices, 3.3.1 Trapping Focus - http://www.w3.org/TR/wai-aria-practices/ |
Your approach does minimize how much of the tabbing behavior we override, The issue you get here though, is what really is the last tabbable element? This was the reason I ended up overriding tab behavior in general, so that We could just use the standard DOM selector to find all the focusable Would it be a bad idea to perhaps add an attribute to the last element (and On Wed, Sep 10, 2014 at 1:29 PM, michelbetancourt [email protected]
|
Your suggestion seems pragmatic. Support first/last focusable element by default. Use an attribute to decorate another element if you're using some tab-index behavior. I'm curious about your example of the close-icon as to why you could not just use DOM order. If its not the first or the last item in your tab order, where does it gain focus? |
@jmwolfe - to emphasise my question about your modals. They seem like they would be similar to the example here: http://accessibility.oit.ncsu.edu/training/aria/modal-window/version-2/ This has a close icon and a cancel button. The keyboard navigation behavior seems completely natural |
@michelbetancourt that is a good suggestion and good find on the WAI-ARIA guidelines doc. I'd have to assume that the WAI-ARIA guidelines are well-researched when they came to that conclusion, but my concern is that you'd still be determining the tab order in the JavaScript (to determine the first/last tabbable element), which is fragile/difficult. Although spec change is a concern, I think the bigger issue would be handling dynamic changes to the tab order. If the last element in the tab order is an Accept/Apply button which becomes disabled based on the validity of form elements in the modal, it will be added and removed from the tabbing order as the validity changes. You'd have to detect this and recalculate the tab ordering to find the new first/last element. Same with changes to tabindex, contenteditable, visibility, and element addition/removal. I suppose you could declare dynamic changes to tab order as unsupported, but that seems likely to bite users. |
Its not difficult to recalculate the tabbable elements with each focus If we incorporate a default DOM order, with an option to override with an If there are any JQuery mavens out there that would care to help On Wed, Sep 10, 2014 at 3:25 PM, Kevin Locke [email protected]
|
@iandotkelly , regarding your question about the close... the close "x" icon is actually the third or fourth element in the DOM list (it's at the top) but I would want to tab there only after the last element on the modal. So I really want it to be last, not 3rd. So I would want my shift=tab to go back to the "X", not to the Cancel button. I can handle this with tabindex, and in this next go-round, I'll handle it in an ng-last-tab directive (well, technically attribute with the dashes). Hope that clarifies. |
Trying to help out with jQuery-fu as you requested. If you're trying to rewrite the focusin handler mentioned above without jQuery proxy etc. Here's one way (assuming $modal refers to the modal element wrapped in
|
And in case it helps, here is a POC based on WAI-ARIA 1.0 Authoring Practices, 3.3.1 Trapping Focus - http://www.w3.org/TR/wai-aria-practices/ http://jsfiddle.net/michelbetancourt/ugkwn1bj/25/ POC uses jQuery and jQuery UI to simplify interaction in this example concept. |
I see what you guys were pointing out earlier. I expanded my POC a bit so see if the WAI-ARIA 1.0 Authoring Practices, 3.3.1 Trapping Focus was still viable in some way. It got a bit complex due to tab-index sorting and the need to update the tabbing index to reflect the intended order after sorting. Anyway in case it helps or inspires here is where I left off with my POC. This POC like the last one includes the cycling feature (going from first to last and last to first): |
Sincere thanks @michelbetancourt and @chrisirhc and everyone for chiming in with the information and examples! This should all be a helpful boost in moving forward with a robust "trapping focus" implementation. If I need to deviate from the approaches we discuss here, I'll bring back any issues to this defect and we'll sort them out, so we don't have any PR surprises later on. Unfortunately, like all of us, I have to squeeze in development on this during weekends and free time, so it may take some time to get a working solution ready. If anyone wants to take this on, I am not going to be offended in the least, and would be happy to help out or review, etc. Just let me know if you do take this on so we don't end up both working at the same time. I think we could also consider collaborating on my cloned repo... i have it clean and ready to work off the latest master. I would just need to figure out how to grant access to others. |
Bonsoir, Pull Request #2920. Manual testing works with Chrome 38/MacOs and Safari 8/MacOs. It doesn’t work with Firefox because of focusin not support. Test with IE will come. For Safari/MacOs and FF/MacOs don’t forget to turn on full keyboard access. Any suggestion/improvement are welcome. |
Hey all, it's been nearly seven months since the last update and nearly two years since this issue was first opened. Are we any closer to an acceptable solution? Thanks. |
…h directions with tab or shift+tab. Refs: angular-ui#738, angular-ui#3689
Really very nicely crafted and explained. @michelbetancourt, @chriswu14 , @jmwolfe |
There is an error in the keypress event binding, if you disable the keyboard (in order to disallow the esc key to close the modal) this event never runs, i think this isnt correct (As i want my modals not to be closed, but i dont want tab to go to the background), here is my fix (in my case i never care about esc key) $document.bind('keydown', function (evt) {
if (evt.isDefaultPrevented()) {
return evt;
}
var modal = openedWindows.top();
if (modal /*&& modal.value.keyboard*/) {
switch (evt.which) {
//case 27: {
// evt.preventDefault();
// $rootScope.$apply(function() {
// $modalStack.dismiss(modal.key, 'escape key press');
// });
// break;
//}
case 9: {
$modalStack.loadFocusElementList(modal);
var focusChanged = false;
if (evt.shiftKey) {
if ($modalStack.isFocusInFirstItem(evt)) {
focusChanged = $modalStack.focusLastFocusableElement();
}
} else {
if ($modalStack.isFocusInLastItem(evt)) {
focusChanged = $modalStack.focusFirstFocusableElement();
}
}
if (focusChanged) {
evt.preventDefault();
evt.stopPropagation();
}
break;
}
}
}
}); Ps. Sorry for my bad english |
@Luukash: Hi there! It sounds like you think you've found a bug. The horror! If so, please follow these instructions so we don't lose this since you're commenting on an already closed (and quite old) issue. Thanks! Unfortunately, if you think you've found a bug and do not follow the above instructions when opening a new issue, we will close the issue due to lack of activity after a reasonable amount of time. |
This can be reproduced on the sample page on http://angular-ui.github.io/bootstrap/
result: tab going through background page and data can also be entered.
Hope someone can advise on this problem. Thanks.
The text was updated successfully, but these errors were encountered: