Open tomalec opened 2 years ago
@tomalec It could be useful to include some screenshots or videos of your hacked solutions.
There have been a few other discussions about TabPanel recently in https://github.com/WordPress/gutenberg/pull/44788 and https://github.com/WordPress/gutenberg/pull/45005, and how it's not very flexible.
or split into more composable parts
This would be my preference, because I think it might allow multiple problems to be solved. Perhaps if the tabs
prop is omitted, components can be used for the tab buttons. That would allow more customization of layout and what the buttons do.
There is also the experimental Navigation
component (https://wordpress.github.io/gutenberg/?path=/docs/components-experimental-navigation--default), and maybe that's closer to what you're looking for.
Thanks for putting together the detailed issue @tomalec 👍
The easiest for us - plugin/extension developers, would be to get a property to just change modes
Personally, I think we should be wary of this approach. I don't believe a TabPanel should allow for navigation between URLs. Adding a simple prop to effectively toggle between two separate components also sounds like it could overcomplicate what should be a fairly straightforward component.
A dedicated component addressing the desired behaviour, e.g. TabNavigation
, would be a better option in my opinion. In the course of achieving that, we still have the opportunity to break down the current TabPanel into some sub-components that could be re-used.
Some extra background on the TabPanel role can be found in these docs. Of particular note is:
Tabs do not act as anchor links to individual panels. While semantic HTML may be coded with the tabs being anchor links navigating to the tab's associated tabpanel, when JavaScript is used to progressively enhance the content to a tabbed interface, the link's default behavior should be prevented.
By that definition of a TabPanel, a navigation=true
prop and navigating to different URLs means it wouldn't be a tab panel anymore.
I'm pretty sure I saw this same topic answered recently, and much more eloquently, by @ciampo but I can't put my finger on the issue where that happened. No doubt, he'll have some wisdom to share here 🙂
Hey @tomalec , thank you for opening this very well-written issue!
I agree that it would be great to have a way to ensure visual consistency between different components — in this case, a tablist + tabpanel component and tab-looking navigation component.
As @talldan mentioned, there have indeed been recent talks about reworking TabPanel
in order to add some requested features — my suggestion there is to rewrite the component using ariakit
under the hood, which would:
Tab
, TabList
, TabPanel
)However, as @aaronrobertshaw explained comprehensively above, when working on such components we need to focus on their semantics first. In that sense, a tab panel and a "navigation menu" (i.e. a list of links that cause the window.location to change when clicked) have very different semantics, and I don't think they make sense as variations of the same component.
A dedicated component addressing the desired behaviour, e.g.
TabNavigation
, would be a better option in my opinion. In the course of achieving that, we still have the opportunity to break down the current TabPanel into some sub-components that could be re-used.
This also feels to me like the best option. We could refactor tab stiles away and apply them to both TabPanel
and a new component — that component could be as simple as a Tab
(ie. a button
with tab styles applied) or a TabNavigation
component (in case there's more functionality needed). If we were to continue with this approach, we'd need to understand first the actual requirements for the component, though.
here is also the experimental
Navigation
component (https://wordpress.github.io/gutenberg/?path=/docs/components-experimental-navigation--default), and maybe that's closer to what you're looking for.
I don't think the Navigation
component is a good match for this — it is quite opinionated for creating nested vertical menus (they kind that are found in sidebars) — plus, it's experimental and I don't think we're planning on iterating on it. We instead preferred a different approach to API design and we applied it in the newer Navigator
component.
Personally, I think we should be wary of this approach. I don't believe a TabPanel should allow for navigation between URLs.
a tab panel and a "navigation menu" (i.e. a list of links that cause the window.location to change when clicked) have very different semantics, and I don't think they make sense as variations of the same component.
I'd totally agree. Tabs are meant to toggle visibility of content in the page (ie. in the same 'resource'). Navigation brings users to a new resource. It's not just semantics. More importantly, it's about the expected interaction behavior the semantics brings in.
Historically, WordPress hasn't made a great use of 'tab-looking navigation' UIs. Think for example at the WordPress About page. Users see a tab-looking design but what they actually get is a navigation menu. As a user, I would expect that activating one of those tabs would just reveal new content in the page. Instead, I'm unexpectedly brought to a new page. To me, a navigation UI should look like a navigation menu. I'd like to suggest to try to learn from the past and not replicate the same design inconsistency that is in core. Unfortunately, many plugins use to replicate this inconsistency (typically on their settings pages) and style their navigation menus like tabs. I'd tend to think that's not a great design, because form doesn't match function.
We could argue on what 'navigation' and 'new resource' actually mean. Maybe I'm a bit old-fashioned but to me a 'new resource' is a new page (or file). New content that appears within a part of the current page is not a 'new resource' that warrants navigation. Worth also noting that a tab-looking navigation
component should also integrate with the browser history API, update the document title accordingly, and announce in some way to screen reader users that a navigation-like interaction occurred. That sounds definitely out of the scope of the TabPanel component.
What problem does this address?
What we have
Currently, the
TabPanel
component uses buttons, to manage dynamic tabbed content, without chaining the page (URL). This serves well for tiny widgets and toolboxes.In many WooCommerce extensions, we would like to use the same UI element to navigate between pages and change URL.
So we would like to have an element, that looks the same, and behaves mostly the same, with a tiny difference it
role=navigation
insteadrole=tabpanel
and<a href>
instead of<button onClick>
The problem is
TabPanel
not only does not enable such a feature, it's also not extendable/composable enough to build such a feature on the top ourselves. (It gets a bit worse as we cannot even control/set the selected tab from the outside/as the consumers of the component: https://github.com/WordPress/gutenberg/issues/27371, https://github.com/WordPress/gutenberg/issues/45390)What we're forced to do
Because of the above, we ended up introducing hacks & workarounds:
<@woocommerce/components.Link>
instead of<@wordpress/components.Button>
document.querySelector
IMO, either workaround is fragile, bug-prone, and not sustainable. In one case, we waste a lot of effort to maintain a clone, test it, and eventually, it still may get diverged from the original impairing end-user experience. On the other, we not only have to spend time to introduce this hack, but it may at any point, unexpectedly stop working, as we are not using public API, or desired use-case, but we're tempering with the details of its implementation, which are only a "manifestation" of its state.
What is your proposed solution?
I think it may be improved by different means.
Simplest for the consumers - new mode/component
The easiest for us - plugin/extension developers, would be to get a property to just change modes, like
<TabPanel navigation=true>
, or another component for such case -<TabNavigation>
. But I guess it may be quite an effort to introduce and maintain a new API from@wordpress/components
perspective.Mid-way - make TabPanel extendable
This idea requires further design. But I imagine
<tabPanel>
could be redesigned (from a software perspective) or split into more composable parts. In a way, I as a consumer could configure or assemble what I need myself.For example to have an element with just a visual layout and styles, then have an element that decorates a given element as "tab", then another high-level element that takes just JSON
tabs
setup and assembles it together. This way to achieve<NavigationTabPanel>
, we would replace/extend only that high-level element.Export styles
If
@wordpress/components.TabPanel
would expose just its styles. We, plugin developers, would still need to "redo" the<NavigationTabPanel>
, but this time, we would be able to use exact same styles, reducing the risk of inconsistent look & feel for end customers.It could be exported as Constructible StyleSheet, plain text, CSS Module, or whatever is usable.
I'm open for any other solution to this problem, or a path to actually use
TabPanel
for navigation. //cc @ciampo