angular / components

Component infrastructure and Material Design components for Angular
https://material.angular.io
MIT License
24.32k stars 6.73k forks source link

Reevaluate tab navigation interaction pattern #23706

Closed jelbourn closed 2 years ago

jelbourn commented 2 years ago

We currently support two interaction patterns for our tabs component: tablist + tab + tabpanel, and nav + anchor.

We've received feedback that the nav + anchor pattern can be confusing, since it looks like tabs, but behaves differently. Furthermore, if these two interaction patterns are mixed, the inconsistency can be confusing for users. These issues would affected users with some degree of vision that use assistive technology to supplement their experience.

We should explore ways to reduce or eliminate the confusion here. Some options include (but are not limited to):

  1. Eliminate the nav + anchor pattern and exclusively use tablist + tab + tabpanel. (i.e. deprecate and remove MatTabNavBar)
  2. Change the visuals of the nav + anchor pattern such that it's more visually distinct
  3. Keep both patterns, but add additional guidance and/or checks to ensure that users aren't introducing confusing behaviors, such as assertions that nav-tabs apply focus management or warning if both are used in the same app.
  4. Change nav-tabs to use tablist + tab while still using anchor elements and routing for the content (i.e., keep MatNavTabBar, but change its interaction pattern)

It's worth mentioning that using anchors is desirable for use cases where you want the URL to change and/or want to support opening in new browser tabs. Using routing to drive tab navigation also easily fits into Angular's route-based lazy-loading system.

cc @zelliott

zelliott commented 2 years ago

What's the difference between bullets 1 and 4? Is 1 remove/deprecate <nav mat-tab-nav-bar> and 4 change it to the tab / tablist pattern?

I scoured the web for some relevant discussion around this design pattern and links that look like tabs:

GOV.UK

There's a lot of good discussion from the GOV.UK team on this.

Other articles


I'm tempted to explore bullet points 2 and 3 a bit. There are plenty of examples around the web of "tab-looking" widgets are just implemented as navigation links. For example:

GitHub

image

Google Search

image

Facebook

image

GOV.UK

image

jelbourn commented 2 years ago

What's the difference between bullets 1 and 4? Is 1 remove/deprecate

Yeah, that was what I meant to convey; I updated the original to clarify.

Based on some of those examples, I have a feeling it would be worth raising this to the Material Design team to explore option two above (changing the visuals of nav tabs) so that, while they kind of look like tabs in general, they're distinctive from the thing that the specification calls tabs (i.e., introduce a new component).

zelliott commented 2 years ago

@jelbourn Just so that I don't forget - one thing that might be worth doing in the meantime is removing the arrow key behavior between links in mat-tab-nav-bar. The links are already separate tab stops, the arrow key behavior is not discoverable to SR users as it is non-standard for links within a navigation landmark, and it may conflict with SR navigation commands.

zelliott commented 2 years ago

After some internal discussion, we've decided to try and run with 4: keep MatTabNavBar, but change its interaction pattern to follow the ARIA tabs pattern. The fact that the two tab components are essentially visually indistinguishable, but have very different interaction patterns, was deemed to be extremely confusing and worth resolving now. I say "try and run with" because I wouldn't be surprised if we hit significant technical challenges with this refactor. More specifically, option 4 involves:

  1. Update matTabNavBar to be an ARIA tablist.
  2. Update matTabLink to be an ARIA tab.
  3. Update the tablist to be a single tab stop and in general be a managed focus region (i.e. home and end to hop between first and last tab).
  4. Update each tab to activate on space (it currently only activates on enter).
  5. Update each tab to apply aria-selected when selected.
  6. Update each tab to have aria-controls pointing to the associated tabpanel.
  7. Wrap the associated outlet in an ARIA tabpanel.
  8. Update the tabpanel to have aria-labelledby pointing to the selected tab.

These requirements are taken from https://www.w3.org/TR/wai-aria-practices-1.2/#tabpanel. Requirements 6-8 will be the most difficult to land because there is currently no tabpanel element. Just leaving this comment here for future reference.

zelliott commented 2 years ago

A few options @crisbeto and I discussed:

  1. Update MatTabNavBar's API to allow the user to content project an outlet inside of it. If outlet is projected, MatTabNavBar has ARIA tab interaction. Otherwise, it has the default ARIA link interaction. Backwards compatible. Wouldn't allow content between nav bar and outlet (which may be a non-starter).
  2. Add a new MatTabNavOutlet component that wraps the outlet. Pass its instance to MatTabNavBar via an [outlet] input. If [outlet] input is specified, MatTabNavBar has ARIA tab interaction. Otherwise, it has the default ARIA link interaction. Backwards compatible.
  3. Update MatTabGroup to (1) support links and (2) support outlets, and (3) separate the "tablist" and "tabpanel" components. Also fully deprecate MatTabNavBar at this point. A ton of work but maybe the north star.
  4. Do nothing.

If we did 2, we could add the new component / update MatTabNavBar in a fully backwards compatible way. Then we could migrate all g3 usages to the new API. Finally we could remove the logic in MatTabNavBar that changes its behavior based upon whether the [outlet] input is specified, and just make the input required.

zelliott commented 2 years ago

@crisbeto, @jelbourn: PTAL at the WIP PR above if you have a sec. It turned out to be pretty easy to implement option 2, and only required 1-2 usage changes in g3. If we do go with 2, would we want to manually migrate all g3 usages to use MatTabNavPanel so that we can remove the logic that defaults to link/navigation semantics if no panel is provided? Or are we comfortable living in a world where MatTabNav can render as either link/navigation or ARIA tabs based upon whether the developer has provided a panel?

angular-automatic-lock-bot[bot] commented 2 years ago

This issue has been automatically locked due to inactivity. Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.