Skip to content
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

fix(tabs): refactor dismissable tab html #16033

Merged

Conversation

alisonjoseph
Copy link
Member

@alisonjoseph alisonjoseph commented Mar 21, 2024

Closes #14820
Ref ##15919

Previously you were only able to dismiss a dismissable tab with the delete key or mouse. This leaves voiceover users on an iphone unaware the dismiss icon even existed.

This is a complete refactor of the html for dismissable tabs, it changes the icon to a button, and moves it outside of the containing tab button and into the tab order. This allows both keyboard and voiceover users to tab to the icon and dismiss the tabs.

Changelog

Changed

  • Convert the dismiss icon to a button, move outside of the tab button
  • Style updates to account for updated html structure
  • Update text for screen-readers to say "remove tab name tab" instead of "close tab"
  • Updated tests
  • Update focus state after tab is removed

Testing / Reviewing

Make sure there are no regressions with any of the tab variants. Be sure to check dismissable in both regular and contained.

Check that the tab order is correct and that the dismiss icon is read on voice over.

Copy link

netlify bot commented Mar 22, 2024

Deploy Preview for v11-carbon-react ready!

Name Link
🔨 Latest commit 2490035
🔍 Latest deploy log https://app.netlify.com/sites/v11-carbon-react/deploys/661447cab273c40008a27835
😎 Deploy Preview https://deploy-preview-16033--v11-carbon-react.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify site configuration.

@tay1orjones
Copy link
Member

Thanks for digging into this! I think it looks good from a code review standpoint.

The landscape around this is kind of a mess. This stackoverflow post explains it pretty well. There's also a big thread about it that hasn't been resolved in w3c/aria#1440

I think this technically doesn't follow WAI-ARIA 1.2 because a tablist should contain a list tab elements.

It adds an additional "Incomplete" entry from `accessibility-checker` image

@tombrunet when choosing between fixing this or following the spec, I think we should side with the user and fix it regardless of what the spec says, but what do you think?

Also, this contains a change that could break tests or custom functionality in consuming applications because of the shift in the DOM. Despite that, I would support shipping this to all users in our next minor without a feature flag due to the severity of the bug.

@mbgower
Copy link

mbgower commented Mar 25, 2024

So, what we're effectively doing is saying that there is an item in the tab order between the tablist and the tab panel, which is "Dismiss current tab". It happens to be shown inside the tab item, but it is effectively outside the tablist.

I wonder if one approach here is to treat this somewhat like the skiptomain function. Rather than put the focus to the X in the tab item, we make a "Delete tab item" that appears to the right of the tablist after a user tabs out of the tablist. Does that solve anything? It suggests to me it would let us solve the discoverability and actionability requirement AND would not violate ARIA. @tombrunet ?

Note that I'm suggesting this as additional behaviour to the current use of a Delete key press. I think we'd retain that, but also provide this.

@tombrunet
Copy link
Contributor

@mbgower The largest problem with that approach is that if you change reading modes on the close button, you are out of context. If I go to the close button and then ask to read the previous word, I expect to hear the name of the tab I'm on, not the name of the last tab in the list.

Looking at some other apps, it does seem that handling of these tab widgets is changing. VS Code has a behavior similar to what Carbon is proposing here (though the close button is only visible for the active tab and on mouse hover). Chrome is actually making every tab widget and close button tabbable.

@mbgower
Copy link

mbgower commented Mar 26, 2024

I also think putting the tablist into an edit function is another potential notion to deal with this.

  1. the tablist works just like any other tablist (single tabstop; arrow between items)
  2. there is an "Edit tab items" button offered for the tablist. I'm going to suggest this could even be a tab item, although that breaks the paradigm a bit
  3. Once the edit button is engage, the users have the ability to delete (or add?) items. One could theoretically also give them the ability to edit the names
  4. The Edit button could toggle to a Save button to complete that mode. Not sure if we need to think about a cancel or confirm (neither of which exist in the current design)

There's even the possibility that rather than deal with these edits in the tablist, the tab panel for the Edit items tab would actually literally be a series of inputs (deletable) for each of the existing tab items. I really don't know how often the delete tab function is used in Carbon products, so have no idea how radical this rethink is

I realize I'm just tossing out ideas here, which is not really to the purpose. I suggest we can continue this at the CAG call on Monday.

@mbgower
Copy link

mbgower commented Mar 28, 2024

@alisonjoseph, I've disrupted your fix with my comments, so I wanted to put in an epilogue on this.

I have a few cautions on the fix which need to be addressed, as well as some suggestions on future changes. But once those issues are addressed (numbers 1 and 3 below) this looks good to go from an accessibility problem when using JAWS. I can do future testing with iOS VO as well. Details below.

  1. ISSUE: It looks like you've implemented this not just on the dismissible tabs, but on ALL the version of Tabs in storybook (default, contained, etc). That shouldn't be happening; it should only exist on the dismissible ones. In the screenshot, you can see that the Jaws red focus indicator is on a small region to the upper right of the Monitoring tab which has nothing there visually. It is announcing this as "close tab button"
image
  1. The implementation on the actual dismissible tab works. In this screen shot, you can see that, after the user presses Tab, Jaws has properly put focus on the X. Good.
image
  1. ISSUE: After activating the X on a tab, the focus goes to the X of the next item; but JAWS does not announce anything. It needs to, at a minimum, now announce the new focus. Note that at the moment, they would again just hear "Close tab button" again, since the message is generic. So that is guaranteed to be confusing. Folks might not even understand anything has happened, and might accidentally re-issue the command again, closing ANOTHER tab by accident. Either you need to rename the tooltip to make it specific (as per a later suggestion) OR, you need to place the focus on the tab, not the delete key, and announce that. I think the latter is my preference, and it meets what the APG states: "If deletion is allowed, deletes (closes) the current tab element and its associated tab panel, sets focus on the tab following the tab that was closed, and optionally activates the newly focused tab."

  2. As I documented in the original issue, ARIA is planning a new attribute aria-actions, which should allow this approach to be possible AND pass current ARIA guidance. @tombrunet and I have both reviewed your refactor and think what you've proposed not only aligns with some vendor approaches, but also seems to align with this direction of aria. Tom's team will figure out what to do with the Checker rules in regard to this version of the dismissible tab component, as it will currently fail a rule, since it does not align with the current aria spec. But it's important to emphasize that it seems to work fine for keyboard and screen reader user.

  3. I would like to suggest that making the message specific to the tab would be useful (i.e., instead of saying "Close tab button" it would say "Close Dashboard tab").

  4. I also wonder if "Close" is the correct verb to use in this tooltip/message. "Remove" or "Dismiss" might make more sense, or even "Delete"? This is a question for the content designer, I guess. My concern is that since a tab does not normally close (or dismiss, for that matter), a user may be unfamiliar with the operation or notion. For example, if I can close something, I can normally reopen it. Not so here.

@alisonjoseph
Copy link
Member Author

alisonjoseph commented Mar 29, 2024

@mbgower thanks for the detailed feedback, I believe I've addressed all of your concerns if you could take another look.

  1. It should no longer be announcing the close button all on tab variants.
  2. Focus should now go to the next tab after removing a tab, and not to the next close button.
  3. Close buttons should now have a specific message and announce "Remove Dashboard tab" instead of "Close tab"

@alisonjoseph alisonjoseph marked this pull request as ready for review April 1, 2024 13:24
@alisonjoseph alisonjoseph requested a review from a team as a code owner April 1, 2024 13:24
@mbgower
Copy link

mbgower commented Apr 1, 2024

@alisonjoseph, all these things have been accomplished, nice!

  • It should no longer be announcing the close button all on tab variants.
  • Focus should now go to the next tab after removing a tab, and not to the next close button.
  • Close buttons should now have a specific message and announce "Remove Dashboard tab" instead of "Close tab"

One thing I noticed is that when the last active tab is deleted (Activity tab), things get a little odd, with either the focus going to the disabled 4th Settings delete button, or focus going up the page.
image
I'd check with @tay1orjones if he remembers the approach we previously discussed about where to place focus in such a situation. I think if it's the last active item and there is a prior item it makes sense to put it there, and that applies if there are no items left at all (i.e., focus would go to Reset). I think that is the basic pattern Josh, Taylor and I discussed many moons ago about what would happen in a table with deletable rows, and the same seems to make sense here as well.

The disabled item may be the curve ball here. It might be an idea to strip that out in some tests and get it to behave predictably with a set of three enabled tabs: what happens if one deletes the LAST item and there are still prior ones available? My expectation would be that the focus would go to the Monitoring tab (the prior one). If you folks concur, is that doable?

Once that makes sense, the disabled component is a bit of an outlier, IMO. I think if there are no more enabled items left, I'd treat it the same as if there were no items left, and got to the prior item?

@alisonjoseph alisonjoseph marked this pull request as draft April 1, 2024 16:36
@alisonjoseph alisonjoseph marked this pull request as ready for review April 2, 2024 17:38
@alisonjoseph
Copy link
Member Author

alisonjoseph commented Apr 2, 2024

I think this is ready for review now. @tay1orjones @andreancardona

@mbgower I've updated it so the previous tab should now take focus after removing a tab. Just wanted to double check that we wouldn't want the active tab to take focus vs the previous one?

@mbgower
Copy link

mbgower commented Apr 2, 2024

@mbgower I've updated it so the previous tab should now take focus after removing a tab. Just wanted to double check that we wouldn't want the active tab to take focus vs the previous one?

I wanted to clarify that I wasn't saying that each time a tablist item is deleted, the focus should go to the prior tablist item; I think 'next tab item, where available' is a good approach, and supports the APG pattern previously quoted.

I was specifically talking about the situation where the last item (or the last non-disabled item) in the tablist is deleted. In both cases, I think it probably should go to the prior tablist item.

It's worth noting that whichever approach you take (focus to next or focus to prior) you're always going to have to have the use case addressed where the intended focus point no longer exists -- i.e., there is no next item, or there is no prior item in the tablist. For that matter, you also need a plan for what happens to focus when there is NO item in the tablist (which theoretically shouldn't be possible, since according to the documentation I think there are supposed to be a minimum of 2 tab items, but I think I've seen it)

@alisonjoseph
Copy link
Member Author

@mbgower ok, focus states are updated.

@mbgower
Copy link

mbgower commented Apr 3, 2024

That's working well with JAWS. I also confirmed it is usable and understandable with VO on iOS. Nice!

Copy link
Contributor

@andreancardona andreancardona left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also tested with Jaws and looks good to me! 🎉

Copy link
Member

@tay1orjones tay1orjones left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@tay1orjones tay1orjones added this pull request to the merge queue Apr 9, 2024
Merged via the queue into carbon-design-system:main with commit 0376df7 Apr 9, 2024
20 checks passed
@carbon-automation
Copy link
Contributor

Hey there! v11.55.0 was just released that references this issue/PR.

@alisonjoseph alisonjoseph deleted the 14820-dismissable-tabs branch April 16, 2024 18:45
preetibansalui pushed a commit to tay1orjones/carbon that referenced this pull request Apr 24, 2024
* fix(tabs): refactor dismissable tab html

* fix: typescript

* feat: add button reset, active state and fix number values

* fix: disabled styles

* fix: styling issues

* fix: fullwidth tabs

* fix: update close to remove & add tab name & hide on non dismissible

* chore: code comments

* fix: tests

* fix: set focus after removing tab

* fix: focus

* fix: set focus to active tab

* feat: update focus state after removing tab

* chore: add code comments

* fix: focus updates

* fix: focus states

* Update packages/react/src/components/Tabs/Tabs.tsx

---------

Co-authored-by: Taylor Jones <tay1orjones@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[a11y]: Tabs [dismissible] - unable to dismiss in iPhone
5 participants