The private Tabs component has a bunch of custom logic that handles a few edge cases:
- Initial tab selection:
- if a
defaultTabId is specified, Tabs will select an initial tab only if there is a tab matching defaultTabId. If there isn't a matching tab, Tabs won't have an initially selected tab. If a tab with a matching id is added lazily, Tabs will select it.
- the initial tab is also used as a fallback when the currently selected tab can't be found anymore. If the initial tab also can't be found, the
Tabs component won't have any selected tab;
- This bunch of logic only applied in uncontrolled mode — the idea being that a consumer controlling the component is in charge of handling these edge cases;
- The currently selected tab becomes disabled:
- the main assumption is that a disabled tab cannot stay as the selected tab;
- In controlled mode,
Tabs assumes that the consumer of the component is in charge of the situation, and therefore it un-selects the previously active, now disabled tab;
- In uncontrolled more, if the currently selected tab becomes disabled,
Tabs falls back to the defaultTabId if possible. Otherwise, it selects the first enabled tab (if there is one).
- In controlled mode,
Tabs will reset the active tab id (ie. no tabs are active) if a tab associated to the currently selected ID can't be found
- If there is no active tab, fallback to place focus on the first enabled tab, so there is always an active element
- It keeps the active id in sync with the currently focused tabs
This custom logic was originally added after observing how the legacy TabPanel component worked, in an effort to cover all edge cases found when using the component in the editor.
As the ariakit library updates and we iterate on the component I am considering removing most (if not all) of this custom logic:
- All of this custom logic is hard to maintain, and it can sometimes cause new unwanted edge cases or unexpected regressions (like during the latest ariakit update);
- The difference between controlled vs uncontrolled behaviour is one more layer of complexity;
-ariakit's latest changes should make sure that a composite widget (like tabs) is always somewhat tabbable, even if the active/selected ID doesn't match an existing DOM element;
- In general, I think we should delegate the handling of such special cases to the consumer of the component, and keep
Tabs focused on providing good tab widgets fundamentals;
My instinct is to remove as much of this code as possible (ideally all of it):
- review whether the current way of handling these edge cases makes sense at all, or is instead a bad practice;
- move edge case handling directly where
Tabs is consumed, if necessary;
@WordPress/gutenberg-components , I'd like to hear your thoughts on this proposal
The private
Tabscomponent has a bunch of custom logic that handles a few edge cases:defaultTabIdis specified,Tabswill select an initial tab only if there is a tab matchingdefaultTabId. If there isn't a matching tab,Tabswon't have an initially selected tab. If a tab with a matching id is added lazily,Tabswill select it.Tabscomponent won't have any selected tab;Tabsassumes that the consumer of the component is in charge of the situation, and therefore it un-selects the previously active, now disabled tab;Tabsfalls back to thedefaultTabIdif possible. Otherwise, it selects the first enabled tab (if there is one).Tabswill reset the active tab id (ie. no tabs are active) if a tab associated to the currently selected ID can't be foundThis custom logic was originally added after observing how the legacy
TabPanelcomponent worked, in an effort to cover all edge cases found when using the component in the editor.As the
ariakitlibrary updates and we iterate on the component I am considering removing most (if not all) of this custom logic:-
ariakit's latest changes should make sure that a composite widget (like tabs) is always somewhat tabbable, even if the active/selected ID doesn't match an existing DOM element;Tabsfocused on providing good tab widgets fundamentals;My instinct is to remove as much of this code as possible (ideally all of it):
Tabsis consumed, if necessary;@WordPress/gutenberg-components , I'd like to hear your thoughts on this proposal