Skip to content

Tabs: ARIA! DO NOT MERGE TO MASTER! #666

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 15 commits into from

Conversation

scottgonzalez
Copy link
Member

This PR is for feedback and should not be merged to master. The default demo is modified for ease of testing. There's a mix of local, disabled, and ajax tabs.

Implementation:

  • Uses a roving tabindex.
  • List items have role=tab, aria-selected, and aria-controls.
  • Panels have role=tabpanel, aria-expanded, and aria-hidden.
  • Ajax tab panels have aria-live=polite, during load they also have aria-busy=true.
  • Keyboard navigation has delayed activation (currently half a second) to allow traversing without activating every panel between where you are and where you're going.
  • Space/enter activates immediately.
  • Ctrl+up while focused is in a panel will move focus to the associated tab. Tab 2 has a focusable element in it.
  • Tabs cannot be collapsed using the keyboard. I wasn't sure about this. On one hand, there's no reason to limit functionality for keyboard users. On the other hand, this could result in users accidentally collapsing content if they press space/enter just after the delay.

Questions:

  • Should users be able to collapse panels using the keyboard?
  • How do users navigate to panels if there's no focusable content?
  • How long should the delay be for the delayed activation?
  • Do any AT devices announce interaction cues that contradict this implementation?
  • Is anything missing/broken?

The demo is changed purely for testing.
Needs tests.
@scottgonzalez
Copy link
Member Author

@hanshillen @ezufelt Can you check this out? You'll need to pull down my fork and test locally.

@ezufelt
Copy link

ezufelt commented May 27, 2012

Hi Scott,

I'm really sorry. I won't have any time to look at this in the near future.

Thanks for all of your work on jQuery UI accessibility.

Everett Zufelt
Accessibility Consultant & Web Developer

Web
http://zufelt.ca
Phone (toll free U.S. & Canada)
1-877-ZUFELT-8 (1-877-983-3588)

Follow me on Twitter
http://twitter.com/ezufelt
View my LinkedIn Profile
http://www.linkedin.com/in/ezufelt

On 2012-05-24, at 8:48 PM, Scott González wrote:

@hanshillen @ezufelt Can you check this out? You'll need to pull down my fork and test locally.


Reply to this email directly or view it on GitHub:
#666 (comment)

@hanshillen
Copy link
Contributor

Hi Scott, please see my feedback below:

  • The Tabpanels must be labeled: They should reference their corresponding tabs using aria-labelledby
  • Tab sorting must be keyboard accessible
  • Tabs can't be removed by keyboard. There should either be a shortcut to do this or the "remove" button should be an actual button that is keyboard accessible and marked up correctly.
  • Text from the close button (and any other content / controls that could be placed inside the tab) ends up being used incorectly as the tab's accessible name. For example, the tabs with a close button inside will be announced as " remove tab" by a screen reader.
    To fix this, the tab's accessible name will have to be explicitly set rather than being calculated by the browser based on the tab's DOM children. There are two ways to do this:
    1. Add aria-label="" to the tab. This is the easiest to implement, but aria-label is not supported on IE so it's not an ideal option.
    2. Add aria-labelledby="" to the tab. This takes a bit more effort because it requires the link inside each tab to be given an ID value, but it does solve the issue. This ID value can then also be used as a target for the tabpanel's aria-labelledby attribute.
  • Disabled tabs do not expose aria-disabled="true"
  • It's still possible to click on a disabled tab and move focus to it. But because it's disabled, the arrow keys don't work. Either disabled tabs shouldn't be focusable, or it should still be possible to move focus to an adjacent tab from a disabled tab.
  • It should still be possible to move focus between tabs in a way that does not select the tab but also is not time sensitive. A screen reader user would never have enough time to hear the tab description, and a mobility impaired user (say a voice input user or single switch device user) or a cognitively impaired user will likely not be fast enough to switch to the next tab before the currently focused tab is activated. So in addition to the delayed reaction, there should be a shortcut that moves focus without selecting the tab. A common shortcut for this is ctrl + down / right to move focus to the next tab, and ctrl + up / left to move focus to the previous tab. Space or Enter can then be used to activate the focused tab.
  • The ARIA best practices also recommend to implement shortcuts for selecting the next or previous panels from anywhere inside the currently opened panel.

To answer your questions:

  • Should users be able to collapse panels using the keyboard?
    Yes, because this feature is most useful as a skipping mechanism for keyboard users. Especially when the tabs contain a lot of elements that are in the tab order. Collapsing the tablist makes it easier to temporarily hide all that and skip past it. You could either make the "select immediately" shortcut to just be be Space rather than Space and Enter, or you could add an additional shortcut for keyboard users to collapse a tab.
  • How do users navigate to panels if there's no focusable content?
    Screen reader users will have to use virtual mode. If the relationship between a tab and its panel is properly marked up, JAWS will say "use JAWS + Alt Key + M to move to controled element". The behavior is a bit buggy, but when it works this shortcut will move the virtual JAWS cursor to the beginning of the tab panel's content. Sighted keyboard users are currently not able to move to the panel contents itself, but may often not need to. The only situation where they would is if the tab panel's content is clipped and requires scrolling. For this scenario it might be useful to make the tab panel focusable, allowing users to tab to is and use arrow, pgup/dn and home/end to scroll the panel contents.

How long should the delay be for the delayed activation?

  • I think this is fine, but I don't have anything to base that on besides my own preference. I think if you made it longer it would make navigation feel sluggish. Provided you also implement the alternative method of moving focus (as described above) having a short delay should be fine. It's mostly a power user feature anyway.

Do any AT devices announce interaction cues that contradict this implementation?

  • JAWS sometimes gives the instruction "to activate tab page press space bar" because of the delayed selection: When the tab is focused it is not selected yet, so JAWS gives instructions on how to select it. By the time it says the the tab is already selected though, so it's no longer applicable. It might be an idea to set aria-selected to true on the focus event rather than on the delayed selection (and to false on blur). While this is technically speaking inaccurate, it could lead to more consistent screen reader behavior.

@scottgonzalez
Copy link
Member Author

@hanshillen Thanks for the detailed response. I'll update accordingly and report back.

@scottgonzalez
Copy link
Member Author

The Tabpanels must be labeled: They should reference their corresponding tabs using aria-labelledby

Fixed in 111e71c.

Tab sorting must be keyboard accessible

Sorting is handled by Sortable and won't be addressed until 2.0.

Tabs can't be removed by keyboard. There should either be a shortcut to do this or the "remove" button should be an actual button that is keyboard accessible and marked up correctly.

There's no built-in support for deleting tabs. This is an update that needs to happen in the one specific demo that implements tab removal.

Text from the close button (and any other content / controls that could be placed inside the tab) ends up being used incorectly as the tab's accessible name. For example, the tabs with a close button inside will be announced as " remove tab" by a screen reader.

Fixed in 111e71c with aria-labelledby as suggested.

Disabled tabs do not expose aria-disabled="true"

Fixed in 111e71c.

It's still possible to click on a disabled tab and move focus to it.

That's annoying. It has tabindex=-1 so it's still focusable. I'll come back to this.

It should still be possible to move focus between tabs in a way that does not select the tab but also is not time sensitive.

We can add ctrl+arrow keys as suggested. There's a collision with ctrl+up/down for paging, but we're already hijacking ctrl+up for moving focus from the panel to the tab anyway.

The ARIA best practices also recommend to implement shortcuts for selecting the next or previous panels from anywhere inside the currently opened panel.

We intentionally don't support that since it breaks browser tab navigation in Firefox. This is even mentioned in the best practices. Ctrl+up, then right arrow is easy enough.

@scottgonzalez
Copy link
Member Author

Should users be able to collapse panels using the keyboard? Yes

Fixed in 9fc48bc.

@scottgonzalez
Copy link
Member Author

It should still be possible to move focus between tabs in a way that does not select the tab but also is not time sensitive.

Fixed in 66c371a. Navigating with the control key will prevent automatic activation.

@scottgonzalez
Copy link
Member Author

How do users navigate to panels if there's no focusable content?
Screen reader users will have to use virtual mode. If the relationship between a tab and its panel is properly marked up, JAWS will say "use JAWS + Alt Key + M to move to controled element". The behavior is a bit buggy, but when it works this shortcut will move the virtual JAWS cursor to the beginning of the tab panel's content. Sighted keyboard users are currently not able to move to the panel contents itself, but may often not need to. The only situation where they would is if the tab panel's content is clipped and requires scrolling. For this scenario it might be useful to make the tab panel focusable, allowing users to tab to is and use arrow, pgup/dn and home/end to scroll the panel contents.

Firefox will automatically put scrollable elements into the tab order. Perhaps we should just leave this alone for now and see if we get any feedback. I'd much rather the browser vendors just implement the Firefox behavior.

@scottgonzalez
Copy link
Member Author

At this point, I believe the only remaining issues for built-in functionality are:

  • Disabled tabs can gain focus, but don't respond to arrow keys.
  • Instructions announced by JAWS.

@hanshillen
Copy link
Contributor

Sorting is handled by Sortable and won't be addressed until 2.0.

There's no built-in support for deleting tabs. This is an update that needs to happen in the one specific demo that implements tab removal.

OK, if it's not part of the widget no need for built in a11y support either. We can think about updating those two demos.

Text from the close button (and any other content / controls that could be placed inside the tab) ends up being used incorectly as the tab's accessible name. For example, the tabs with a close button inside will be announced as " remove tab" by a screen reader.

Fixed in 111e71c with aria-labelledby as suggested.

Confirmed

Disabled tabs do not expose aria-disabled="true"

Fixed in 111e71c.

Confirmed

It's still possible to click on a disabled tab and move focus to it.

That's annoying. It has tabindex=-1 so it's still focusable. I'll come back to this.

Probably easiest to just counter this by adding a mousedown handler to the disabled tab and calling event.preventDefault() in it.

It should still be possible to move focus between tabs in a way that does not select the tab but also is not time sensitive.

We can add ctrl+arrow keys as suggested. There's a collision with ctrl+up/down for paging, but we're already hijacking ctrl+up for moving focus from the panel to the tab anyway.

Another option would be to only support Ctrl + Left / Right and not the vertical keys. But that may be confusing if the widget will some day be configurable as a vertical tab list.

Fixed in 66c371a. Navigating with the control key will prevent automatic activation.

Confirmed, it's working well. JAWS is doing some odd things with the announcement here though. first It's announcing the tab normally, but then it adds "move tab left" or "move tab right", and announces the tab all oiler again. I'm assuming this is just a JAWS quirk.

The ARIA best practices also recommend to implement shortcuts for selecting the next or previous panels from anywhere inside the currently opened panel.

We intentionally don't support that since it breaks browser tab navigation in Firefox. This is even mentioned in the best practices. Ctrl+up, then right arrow is easy enough.

I agree about the conflicting shortcuts, but you can still consider implementing something else. I used Alt + PgUp and Alt + PgDn which is much less conflicting

Firefox will automatically put scrollable elements into the tab order. Perhaps we should just leave this alone for now and see if we get any feedback. I'd much rather the browser vendors just implement the Firefox behavior.

OK

Should users be able to collapse panels using the keyboard? Yes

Fixed in 9fc48bc.

The collapse function now works with both Space and Enter. Didn't you say you felt that conflicted with the delay canceling shortcuts (also Space and Enter)?


Reply to this email directly or view it on GitHub:
#666 (comment)

@scottgonzalez
Copy link
Member Author

Thanks for confirming those changes.

Probably easiest to just counter this by adding a mousedown handler to the disabled tab and calling event.preventDefault() in it.

Yup, except that this doesn't work cross-browser. In IE, you can't prevent moving focus inside of mousedown and the focus moves asynchronously, so it's a huge pain to work around.

I agree about the conflicting shortcuts, but you can still consider implementing something else. I used Alt + PgUp and Alt + PgDn which is much less conflicting

Ok, we can add that.

The collapse function now works with both Space and Enter. Didn't you say you felt that conflicted with the delay canceling shortcuts (also Space and Enter)?

Yes, my concern is that users may try to cancel the delay but be just a bit too slow and then end up collapsing. If we make space not collapse, would enter still cancel the delay? Are there stats about how people normally activate elements (space vs. enter)?

@hanshillen
Copy link
Contributor

Probably easiest to just counter this by adding a mousedown handler to the disabled tab and calling event.preventDefault() in it.

Yup, except that this doesn't work cross-browser. In IE, you can't prevent moving focus inside of mousedown and the focus moves asynchronously, so it's a huge pain to work around.

That's strange, I tried it out in IE9 and it seemed to work. I used the following line on your demos/tabs/default.html demo:

$("#ui-id-3").mousedown(function(event){event.preventDefault();});

Yes, my concern is that users may try to cancel the delay but be just a bit too slow and then end up collapsing. If we make space not collapse, would enter still cancel the delay? Are there stats about how people normally activate elements (space vs. enter)?

I don't have any stats no. Traditionally Space is for toggling (e.g. checkboxes) and Enter is for Activating (e.g. links). So using Space for collapsing and expanding the tab list and Enter for immediately activating the tab (canceling the delay) would make sense to me (I realize I said the opposite initially, so disregard the earlier statement about Enter and Space). Of course whatever you do some people going to be confused. I'm really starting to wonder if it would make sense to have a consistent shortcut (either built into widget or as a separate plugin that developers can add) that can be used to get context sensitive instructions about how to use the currently focused widget. The instructions could be a tooltip in combination with a live region for example, or a dialog popping up. But that's outside the scope for this PR of course.

@scottgonzalez
Copy link
Member Author

That's strange, I tried it out in IE9 and it seemed to work.

Sorry, I should've been more specific. IE 6/7/8 have this issue. Newer IEs work as expected, though they still have async focus, but that's not an issue if we can prevent focus.

@scottgonzalez
Copy link
Member Author

Traditionally Space is for toggling (e.g. checkboxes) and Enter is for Activating (e.g. links). So using Space for collapsing and expanding the tab list and Enter for immediately activating the tab (canceling the delay) would make sense to me...

Ok, that makes sense. I've made this change in 6fe06fa. Enter will only activate and not collapse. Space will toggle the focused tab, so if it's pending activation it will activate, if it's already active it will collapse, and if it's collapsed it will open.

@scottgonzalez
Copy link
Member Author

Added alt+page up/down in 3d735cf.

@scottgonzalez
Copy link
Member Author

Probably easiest to just counter this by adding a mousedown handler to the disabled tab and calling event.preventDefault() in it.

Implemented, with work around for IE in 1f0ea5b.

@scottgonzalez
Copy link
Member Author

@hanshillen Can you confirm that everything is working as expected now? The only issue that should still exist is the announcement that JAWS makes about pressing space bar to activate. Is there any indication to the user that the tab has already been activated after JAWS announces the instructions?

@hanshillen
Copy link
Contributor

Hi Scott, it's mostly working as expected now, besides some JAWS oddities and some of the features (such as collapsible sections) not being communicated to screen reader users.

Some remaining feedback:

  • You should also support the alt + PgUp/PgDn shortcuts on the tablist itself for consistency's sake (if a keyboard user wants to switch three tabs to the left from within a tab panel it's more intuitive to use the same shortcut three times than to have to use one shortcut for the first adjacent tab and another for the second and third tab).
  • It's still possible to cancel the delay with the Space key, leaving the possibility for a conflict with the toggle behavior for collapsible tabs. But I think you deliberately left this in, right? I initially thought you were going to make Space for collapsing only and Enter for activating only.

@scottgonzalez
Copy link
Member Author

You should also support the alt + PgUp/PgDn shortcuts on the tablist itself for consistency's sake (if a keyboard user wants to switch three tabs to the left from within a tab panel it's more intuitive to use the same shortcut three times than to have to use one shortcut for the first adjacent tab and another for the second and third tab).

That makes sense. I'll add it.

It's still possible to cancel the delay with the Space key, leaving the possibility for a conflict with the toggle behavior for collapsible tabs. But I think you deliberately left this in, right? I initially thought you were going to make Space for collapsing only and Enter for activating only.

It doesn't seem to make sense to me for Space to toggle but not activate. Space means toggle, if you press it while navigating with the arrow keys and the tab has not already been activated then you're toggling it on.

@scottgonzalez
Copy link
Member Author

You should also support the alt + PgUp/PgDn shortcuts on the tablist itself for consistency's sake (if a keyboard user wants to switch three tabs to the left from within a tab panel it's more intuitive to use the same shortcut three times than to have to use one shortcut for the first adjacent tab and another for the second and third tab).

Fixed in 6b4457c.

@scottgonzalez
Copy link
Member Author

Perhaps we should remove the delayed activation now that we support ctrl+arrow keys. The main reason I wanted this was so that users could navigate quickly without needlessly activating lots of tabs in the process (especially useful for ajax tabs). Navigating with control isn't really discoverable though, so I don't have too strong of a feeling either way. However, I believe this would address some issues with JAWS announcements without resorting to hacks. Is that correct @hanshillen ?

@scottgonzalez
Copy link
Member Author

@hanshillen and I just had a very long discussion about the delayed activation. We decided that the world sucks and nobody should be subject to implementing this stuff...

There are three models:

  • Immediate activation - ARIA authoring practices
  • Manual activation - Yahoo! Mail
  • Delayed activation - OS X

Immediate activation has the benefit of being how most desktop tabs work. AT expect tabs to behave this way, and we get the most accessible solution for blind users. JAWS is able to announce that you can move focus from the tab to the panel because all state changes immediately. When the tab gains focus, it has aria-selected=true and the panel (associated via aria-controls) is visible. The downside is that you cannot navigate across ajax tabs using the keyboard without activating all tabs as you navigate.

Manual activation is a bit odd. It's very web-like (think about how tabs work now where you use the tab key to move between tabs and then press enter to activate, except that you use arrow keys instead of tab). Yahoo! Mail does this and Victor Tsaran thinks this is ok. They use aria-describedby to provide specific instructions that you should press enter to activate. The fact that enter activates instead of space is also strange, as desktop tabs do not work that way. I've always viewed Yahoo's mindset as ARIA by default is bad because it changes web behavior. I don't know if that's their official stance, but it would explain the behavior they implemented here.

Delayed activation is really nice for sighted keyboard users because they can quickly navigate across tabs without activating tabs in the process. This isn't useful for blind users because they can't possibly hear the tab labels before the delay finishes and the tab activates. Additionally screen readers get confused about the state of the tabs because at the time that the tab gains focus it still has aria-selected=false. Interestingly, OS X deals with this by changing the behavior when VoiceOver is on. As soon as VoiceOver is turned on, native tabs switch from delayed activation to manual activation.

We've decided to stay with delayed activation, but set aria-selected=true immediately so that when the screen reader announces the tab it says that it's selected. This is technically a lie, but all will be right in the world in 300ms :-) We've also corrected our mistake and made space activate and enter toggle (enter is just an addition, but space activating is expected). This matches the native behavior and the announcement from JAWS. However, by staying with the delayed activation, JAWS does not announce the relationship created by aria-controls because at the time that the tab gains focus the panel is still hidden. This is unfortunate, but not broken. If the user tabs away and then tabs back, the relationship is announced since the panel is visible. We also address the activating ajax tabs issue by allowing navigation while holding the ctrl key to prevent automatic activation. The big downside to this is that it's not discoverable.

@scottgonzalez
Copy link
Member Author

I'm going to write tests for this, update the wiki and then squash this into master. Finally.

@scottgonzalez
Copy link
Member Author

Landed in 48588d3 with tests in 47a427e, 4cacb4b, e1eeed6, db5f95f.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

4 participants