Keyboard users who attempt to use the Panels IPE (or Page Manager, although it has even more problems) to add or configure panes will get caught in a keyboard trap that prevents them from accessing the links and fields in the CTools modal.
The trap is mitigated by the fact that the Esc key closes the modal, but it doesn't look like there's any way to add or configure panes without using the mouse. This is also an issue for screenreader users, but the screenreader functions that allow searching for text strings or links and navigating within the page from the location of the matching text are a big help (although, how could you possible know what to search for?). I was not able to find a similar workaround using only the keyboard on Firefox/Mac.
While this issue is focused primarily on fixing the Panels IPE use-case, these problems affect any use of the CTools modal! By fixing the modal itself, we'll automatically make everything that uses the CTools modal a little more accessible (although, that's not to say that they couldn't to something else that hurts accessibility).
System setup and configuration:
- Drupal 7.34
- CTools 1.x-dev (revision fb6c216)
- Panels 3.x-dev (revision cd0ded6)
- Panelizer 3.1
- Panels In-Place Editor 1.4
- Bartik 7.34 set as front-end theme
- Seven 7.34 set as admin theme
- Node view page enabled in Page Manager
- Panelizer configured for the Basic Page content type - full page override, provide default panel, render with IPE, single-column default layout
- One node of type Basic Page created and saved
To reproduce:
- On the Basic Page node, tab to and activate the Customize this page button
- Tab to and activate the Add new pane button
- Note that a modal overlay appears with a Close link and a set of vertical tabs and links
- Without tabbing or mousing anywhere, hit the Enter key
- Note that the modal overlay disappears and then appears again, implying that keyboard focus is still on the button that activated the overlay
- Using the Tab key, try to navigate to the first vertical tab
- Note that no matter how many times you hit Tab, focus does not appear to change (I tried about 50 tabs)
- Use the Esc key to exit the modal overlay
- Repeat the above process and try Shift+Tab to navigate backwards
- Note that no matter how many times you hit Shift+Tab, focus does not appear to change (also tried about 50 tabs)
This problem occurs with the Add pane functions, the Settings functions, and the Style functions.
Here is a link to simplytest.me that you can use to launch a test site to verify the problem:
http://simplytest.me/project/ctools?add[]=panels&add[]=panelizer
Solution:
When the user activates the CTools modal, move the keyboard focus to the Close Window link. Constrain tabbing to within the modal, so tabbing forward after the last focusable element will return to the beginning of the modal.
To fully fix this in the Panels IPE and Page Manager use cases, this Panels patch is also necessary: #2390803: Keyboard focus should be on the first element in the selected category tab in the "Add content" model (accessibility problem)
Unfortunately, since two patches on two different projects (CTools and Panels) are required to test the solution, we can't make a simplytest.me link for that. :-/
| Comment | File | Size | Author |
|---|---|---|---|
| #37 | interdiff-2280853-34-37.txt | 1010 bytes | cboyden |
| #37 | ctools-keyboard-trap-2280853-37.patch | 8.32 KB | cboyden |
Comments
Comment #1
cboyden commentedComment #2
mgiffordNice description.
Comment #3
cboyden commentedLooks like this might be caused by the ctools modal.js function - moving to ctools.
js/modal.js, line 403-428:
Since keyboard focus is still on the button that opens the modal (see steps 4 and 5), the keyboard focus target is not within the modal and thus all keypresses except Esc, which is bound to the Close button, are getting discarded.
Comment #4
cboyden commentedAs a proof of concept, I added
$('.close').focus();to modal.js just before the lines that bind focus and keypress events to the modalEventHandler function. With this in place, I was able to tab forward through the links on the Add Content modal in the Panels IPE. When I activated one of the links, I was caught in the keyboard trap again.
Comment #5
mgiffordComment #6
cboyden commentedThis trap is an issue on Firefox (Windows, Mac, and Linux) but not on Chrome (W/M/L), Safari (M), or IE 11 (W).
For Safari, Chrome and IE, usability would improve if focus was set to the Close button when the modal opened. Otherwise there are a ton of keystrokes involved.
Comment #7
mgiffordWas any of the code responsible ported over to D8 Core? I know not all of Ctools was but believe some code has been brought over with Views into Core.
Comment #8
dsnopekHere is a first pass at a patch for this. It still needs lots of work and TONS of testing, but it's a start. :-)
Comment #9
cboyden commentedI tested this patch on Chrome/Mac on a vanilla install of the latest Panopoly dev. It's looking pretty good there. One thing that I found was that it was possible to tab forwards out of the modal settings dialog in some cases, but not backwards.
To reproduce on a clean install of Panopoly with demo content:
Firefox/Mac will still need some work. With or without the patch, I can't tab to anything except the navbar menu and the Customize/Save etc. IPE options at the bottom of the page.
Comment #10
dsnopekHere is a related patch to Panels that allows the "Add content" dialog to work with this (for me) under Chrome, using straight Panels (not Panopoly): #2356449: Content type buttons not focusable under Chrome (accessibility problem)
Comment #11
dsnopek@cboyden: I'm able to reproduce the issue you found under Panopoly, however, I haven't come up with a way to do it in straight Panels. I'm not sure what the problem is exactly - it could be some CSS or template changes that Panopoly is making OR something specific to radio buttons in Firefox. I originally thought it might have to do with the live previews, but I disabled that and could still reproduce.
Anyway, unless we can reproduce this on straight Panels, it should be become a follow-up Panopoly issue after this one is finished.
Comment #12
cboyden commentedI found another tabbing bug where it's possible to tab backwards out of the modal. This is in plain Panels.
Code:
Modules enabled:
Patches:
Config
This is on Mac OS X 10.9.5 with Firefox 32.
Tabbing backward once you've selected a vertical tab will send you out of the modal. To reproduce:
There's also a conflict with Admin Menu/Toolbar Style. To reproduce:
Expected behavior in both cases:
Once you've activated a vertical tab, tabbing backward should focus you on the previous tab. If there are no previous vertical tabs, focus should be on whichever focusable element is before the vertical tabs. In this case, that's the Close Window link.
Comment #13
cboyden commentedRelated to the above: Once you've activated a vertical tab, when you tab forward once, you always focus on the first vertical tab (Activity in this case).
To reproduce:
Expected behavior:
Focus should be on the first link in the Comment section (preferred), or on the next vertical tab. If there are no further vertical tabs, focus should be on the next link after the vertical tabs.
Comment #14
cboyden commentedThe previous issues also apply to Safari 7.0.6, Firefox 33, and Chrome 38 on Mac OSX 10.9.5, and the same Chrome and Firefox versions on Windows 7.
The problem with tabbing backward doesn't happen on the first load of the ctools modal, but once you've activated a link, it will happen on any state of the modal.
Comment #15
cboyden commentedWhen using IE 11 on Windows 7:
So for IE 11, the backward tabbing issue happens even on the initial state of the modal.
Also, the issues are different after you've activated a link in the modal. To reproduce:
However, if you tab backward after activating a link, tab focus moves back to the last focusable element in the modal. To reproduce:
It appears that IE 11 has the opposite problem from FF and Chrome: it handles backward tabbing OK after you've activated a link, but not forward tabbing.
Comment #16
cboyden commentedWhat's probably happening is that when you click a link in the modal, it's changing the state and losing where it should be focused. Focus then tries to go back to the Close button like it does on first load, but something is interfering so it doesn't look or behave like Close is actually focused. Then different browsers interpret where it's actually focused differently, which creates the differing behavior when you tab forward or back.
Comment #17
dsnopekSo, first let's just start by focusing on problems on Chrome (we can do the other browsers after - it'd just be nice to have one browser working to start with).
This is because clicking a tab reloads the entire content of the modal - not just the area on the right. So, the DOM element it was previously focusing on is no longer on the page! I'm not sure we can fix this in CTools - it might need to be fixed in Panels, by either changing how much of the modal is reloaded or by explicitly focusing on the selected category after the reload has happened. I'll try and find a solution to this...
I think these are all the problems reported that affect Chrome! @cboyden: Please let me know if I missed any!
All my testing was on Chrome 39.
Comment #18
dsnopekAlright! I created a Panels issue to fix #17.1:
#2390803: Keyboard focus should be on the first element in the selected category tab in the "Add content" model (accessibility problem)
And here is an updated patch for this issue which should fix #17.2 and .3.
Please let me know what you think!
Comment #19
cboyden commentedVery nice. I tested on Mac OSX 10.9.5 with Chrome 39.0.2171.95, Firefox 34.0.5 and Safari 7.1 and have so far been unable to break anything or get myself into a keyboard trap. I added, configured, and deleted panes using the IPE successfully on those three browsers.
However, I ran into these same issues when adding panes using the Page Manager interface instead of the IPE (trapped in Firefox; able to tab out of the modal in Chrome and Safari). Hopefully it's not too hard to add these fixes to the content modals in Page Manager.
Code and patch status for my testing:
Code:
Modules enabled:
Patches:
Config:
Comment #20
mgiffordOk, so with SimplyTest.me we can capture this all this with the following.
That gave me a - Error message: An error occurred while patching the project.
Comment #21
cboyden commentedHow do you specify the dev version of a contrib project on simplytest.me? The patches might only apply correctly using the dev version of Panels.
Comment #22
cboyden commentedOr, does simplytest.me attempt to apply all patches to the main project you choose? Since patches are not explicitly associated with the projects you can add, this is probably what's happening. So it doesn't sound like you can apply patches to more than one project, which makes this not a good candidate for simplytest.
Unless you generated the patch(es) from the Drupal site root. Then as long as simplytest puts the modules where you expect them, you could have it patch the whole shebang. That would clutter up the issue queue with patches that were doomed to fail, so they'd have to be uploaded elsewhere.
Comment #23
dsnopekHere is an updated patch that fixes the issue that @cboyden found on Panopoly in comment #9. It's not actually Panopoly-specific, the issue will happen any time the last focusable element on the page is a group of radio buttons, and any radio button other than the last one is selected (if the last one is selected, everything works fine).
The cause is jQuery's
:tabbablepsuedo selector returning all radio buttons, when in fact, only the selected radio button in a group is tabbable, and if no radio buttons in a group are selected, then only the first is tabbable. So, I've added a function (getTabbableElements()) that will filter out the un-tabbable radio buttons.This should now resolve all the problems discovered on this issue so far! Please let me know what you think.
Comment #24
cboyden commentedThe latest patch fixes the issue with radio buttons in the modal.
Comment #25
cboyden commentedThis is looking great in the IPE. Using the Page Manager interface, somehow the fix isn't working. After activating one of the links for a type of content, the symptoms are the same as before the patch. I can't tell if the problem is in this JS or in the fix for #2390803: Keyboard focus should be on the first element in the selected category tab in the "Add content" model (accessibility problem).
Comment #26
dsnopekCopying @cboyden's comment from #2390803-7: Keyboard focus should be on the first element in the selected category tab in the "Add content" model (accessibility problem) for the bits that mainly relate to this issue:
Step #9 pertains to #2390803: Keyboard focus should be on the first element in the selected category tab in the "Add content" model (accessibility problem) which we'll address there.
But step #10 and #11 represent issues that this patch should address.
Comment #27
dsnopekI'm testing with a vanilla Drupal 7.34 site, CTools 1.x (fb6c216) + this patch and Panels 3.x (cd0ded6) + the latest patch from #2390803: Keyboard focus should be on the first element in the selected category tab in the "Add content" model (accessibility problem).
Following the steps in #25, testing on Chrome 40.0.2214.91 and Firefox 34.0 (both under Linux), I'm unable to reproduce: the keyboard focus is correctly restricted to the modal. Unfortunately, I don't have Safari to test.
So, setting back to "Needs review". Could you give it a try with the more recent Git revisions and the latest patch from #2390803: Keyboard focus should be on the first element in the selected category tab in the "Add content" model (accessibility problem) and see if you're still seeing the same problems? Thanks!
Comment #29
cboyden commentedTested on Firefox 35.0.1 on Mac. I've narrowed down the problem to jQuery errors which are interfering with the tab constraints code (this ticket) and the focus on the first element (linked ticket #2390803: Keyboard focus should be on the first element in the selected category tab in the "Add content" model (accessibility problem)). The errors are:
This is using the standard jQuery version that comes with vanilla Drupal, 1.4.4. I tried updating to jQuery 1.7.1 and got the same errors.
Since the exact same code runs without a hitch when using the IPE, I'm guessing the error is actually somewhere further up the stack?
Here is a stack trace from Firebug:
And from the Chrome dev tools:
Comment #30
cboyden commentedThis may be it: When the core Overlay is disabled, I get the jQuery error. When it's enabled, I don't, and the code works as intended. @dsnopek can you try disabling Overlay on your test site and see what you get? I also updated the referenced ticket #2390803: Keyboard focus should be on the first element in the selected category tab in the "Add content" model (accessibility problem).
Comment #31
dsnopekGreat catch! I explained what this is about over in #2390803-13: Keyboard focus should be on the first element in the selected category tab in the "Add content" model (accessibility problem).
Here is a new patch that should fix it!
Comment #32
cboyden commentedI think this is finally it! The only issue with the patch in #31 is that IE 8 does not support the indexOf function on arrays. Using the jQuery $.inArray function is working for me, as tested using IE 11's developer tools set to IE 8 mode. Patch and interdiff are attached.
Comment #33
cboyden commentedI have one more problem when using IE/Windows: Focus is not always corralled properly or does not appear where I expect it. Issues are similar between Windows 7/8.1 and IE 8 thru 11. They happen both on the Panelized/IPE node and on the Page Manager page.
Here's what happens using Win7/IE11 on the Panelized/IPE node:
Comment #34
dsnopekI was able to reproduce this on IE11.
The issue with the the "Close Window" link not getting focus (steps #1-4), was from a left over line of code that gave focus to
#modalContentwhich came after my new line of code giving focus to the close button. I have no idea why this didn't happen on other browsers! Possibly only IE actually allows that div to be focused? In any case, I've removed that line.This also had the side effect of fixing the issue where tabbing backwards would select the second to last item (steps #5-6).
The remaining issue where focus escaped the modal was much more complicated. It appears that IE acts differently than Chrome and Firefox when focus is lost entirely. It will put focus on nothing, so pressing TAB will move to the first tabbable element on the page (which is the "Skip to main content link") and it also won't fire events registered on the body. So, our event handler has no chance to catch this TAB and force us back to the modal. (And, also, when "Skip to main content link" is focused, it matches our heuristic for detecting if another dialog is in use, so we don't do our magic then either - that's why you have to TAB a couple of times to get back to the modal).
This means that the only way to fix this in IE, is to try and make sure that focus ISN'T lost entirely.
So, I added some code to the AJAX responder for the
modal_displaycommand, to put focus on the first tabbable element in the dialog, when we are replace existing contents of an already visible modal. This will catch the case where we switch to the settings form when adding a new Pane, and I think it's a good improvement for accessibility on its own, we just haven't gotten there yet. :-)New patch is attached! Please let me know what you think.
Comment #35
cboyden commentedThe functionality is working as expected. Tested on Win7/IE11 plus emulation of IE 8, 9, and 10 using the IE developer tools.
However, the script is now throwing Javascript errors on all browsers/platforms I tested (Mac: Chrome and FF; Windows: IE) in specific circumstances. Here's what happened:
or
The errors also occur after any operation that involves saving something in the Add/Configure modal.
I did not see the errors under these conditions:
Tabbing through the admin toolbar menu did not generate errors. Errors disappeared after reloading the page and did not recur until I did something that involved saving pane settings in the Add/Configure modals.
Comment #36
cboyden commentedLooks like maybe the tab trap handler isn't getting unbound like it should? I'll take a shot at fixing this.
Comment #37
cboyden commentedOK, maybe this is IT it. The tab trap handler was not getting unbound when the modal closed other than by the explicit Close Window link - i.e., when the modal disappeared after you clicked Finish. In order to allow it to unbind, I had to change the scope of the modalTabTrapHandler by removing 'var'. I also added an explicit unbinding of the Escape handler. New patch and interdiff are attached.
Comment #38
cboyden commentedComment #39
dsnopekI'm able to reproduce the Javascript errors that @cboyden found by following the steps in #37. And I can confirm that her updated version of the patch fixes them!
At this point we've tested all major browsers and got everything working in very many cases, however, I'm not sure that review by either @cboyden or myself is really enough to RTBC this. I cleaned up the issue summary a bit and I'm going to see if I can find some other people to test and review the patch.
Comment #40
dsnopekSomething I noticed when updating the issue summary: it originally said we should use the ARIA role of "dialog" on the modal overlay. This patch doesn't do that - is it something we should still do?
Comment #41
dsnopekAdded a link to simplytest.me to verify the problem:
http://simplytest.me/project/ctools?add[]=panels&add[]=panelizer
Unfortunately, since two patches on two different projects are required to test the solution, we can't make a simplytest.me link for that. :-/ Maybe if we can get the Panels patch committed, this will possible: #2390803: Keyboard focus should be on the first element in the selected category tab in the "Add content" model (accessibility problem)
Comment #42
klu commentedThanks @dsnopek and @cboyden! I have done additional BrowserStack testing in Windows XP, 7, and 8 with IE 8, 10, 11, and can confirm that keyboard behavior is working properly.
Comment #43
dsnopekDiscussed with @cboyden and decided save the ARIA stuff for a dedicated issue to ARIA things up! Removing that from the issue summary.
Comment #44
japerryAdded to my list of stuff to review for 1.7 (maybe 1.8)
Comment #45
damienmckennaComment #46
micnap commentedI'm on Mac OS X and tested in Chrome 41, FF 36.0.4, and Safari 7.0.3 with and without overlay enabled.
Tested using latest core and contrib modules:
Core 7.35
CTools 7.x-1.7+1-dev
Page manager 7.x-1.7+1-dev
Panelizer 7.x-3.2-beta1+21-dev
Panels In-Place Editor 7.x-3.5+0-dev
Panels 7.x-3.5+0-dev
Patch from #37
Patch from https://www.drupal.org/node/2390803#comment-9585245
Patch from https://www.drupal.org/files/issues/panels-chrome-a11y-2356449-1.patch was committed so I didn't have to apply.
Used the config from #19:
Node view page enabled in Page Manager
Panelizer configured for the Basic Page content type: full page override, provide default panel, render with IPE, single-column default layout
One node of type Basic Page created and saved
One Page Manager page created
All worked beautifully! When the modal opened, the focus was immediately on the Close Window link in the modal. Tabbing took me through the categories. I entered a category and tabbed through the category's items. All tabbing stayed within the modal. When I closed the modal without adding content, focus returned to the Add New Pane button. When I added content, the focus returned to the top of the page when the modal closed. This worked when adding content to both panelizer and page manager.
This is a great step forward in the accessibility of Drupal!
Comment #47
dsnopek@micnap: Thanks so much for testing!
Comment #49
japerryThanks everyone for the hard work here! Committed!
Comment #51
dsnopekWoohoo! It's great to see this EPIC issue finally get finished. :-)