chakra-ui / ark

Ark UI is a headless UI library with over 45+ components designed to build scalable Design Systems that works for a wide range of JS frameworks.
https://ark-ui.com
MIT License
3.76k stars 103 forks source link

[TabList] [Vue]: as controlled component #916

Closed jiblett1000 closed 1 year ago

jiblett1000 commented 1 year ago

Description

This is something I think would greatly increase the flexibility of the Tabs component, particularly when using Tabs as a controlled component.

Essentially, sometimes it would be useful to use TabList elsewhere in the dom (a header outside of the page content for example), but still take advantage of say, the TabIndicator functionality.

Proposed Solution or API

If TabList also allowed the ability for it to be treated as a controlled component, you could sync both the Tabs and TabList components to the same ref while having them in separate locations.

Additional Information

No response

Shyrro commented 1 year ago

Wouldn't using Teleport solve this actually ? You could teleport it wherever you want in the DOM

jiblett1000 commented 1 year ago

@Shyrro I gave that a shot, but it didn't seem to work for me. I'll give it another go today just to be sure though.

jiblett1000 commented 1 year ago

@Shyrro Yeah. Looks like user error on this one. Teleport was having trouble finding the element. I didn't realize I had to wrap it in <ClientOnly> to be able to teleport it somewhere besides body. As per:

https://nuxt.com/docs/api/components/teleports#example-client-side-teleport

Anyhow, closing as this doesn't seem particularly necessary anymore :smile:

jiblett1000 commented 1 year ago

Hmmmm, sorry. Actually reopening as this disappears the TabIndicator for some reason.

Shyrro commented 1 year ago

@jiblett1000 Could you provide a sandbox that will help us debug this? Thanks

jiblett1000 commented 1 year ago

@Shyrro Will do. I've gotta get some zzz's right now, but I'll do it when I awake :sleeping:

jiblett1000 commented 1 year ago

@Shyrro Ok, all done:

https://stackblitz.com/edit/nuxt-starter-hfdngb?file=app.vue,components%2FCustomTabs.vue,package.json,nuxt.config.ts

If you remove ClientOnly and Teleport from around TabList, the tabs work as they normally would. Also, having just ClientOnly (without teleport) causes the (no indicator) issue as well.

jiblett1000 commented 1 year ago

@Shyrro I realized I should've wrapped the entire tabs component in ClientOnly :hand_over_mouth: , not just the Teleport. Doing so fixes the TabIndicator issue. I'm going to close this as I'm not aware of any other issues with this for now.

Shyrro commented 1 year ago

@jiblett1000 Sorry for getting back late to you. Great to hear this is solved !

jiblett1000 commented 1 year ago

@Shyrro Don't mean to beat a dead horse, but in the process of reworking the layout of my app, I've come across this issue again and think there is still a use-case for a controlled TabList component.

While wrapping the Tabs component in ClientOnly does allow me to teleport TabList elsewhere in my app, this is not a very robust solution.

  1. Using teleport requires the teleport location isn't within the same component. Let's say I have a page component and just want to put the TabList in a header element at the top of my page component; This is not possible with teleport as the teleport location cannot be within the same component. If I want to customize the "header" on a per-page basis, this forces me to alter the structure of my app (with potentially negative compromises or complications).

  2. In the case of using SSR; This becomes impossible without using ClientOnly as Teleport either can't find the teleport location or results in hydration errors. And, if using ClientOnly, this eliminates SEO for the tab component entirely.

I think all of these pain points could be eliminated by having the option of using the TabList as a controlled component and usable outside of the Tab component structure. While I could probably try and recreate the TabList component for this, I'm sure there would be gaps in the accessibility and in general it wouldn't take advantage of the great work that you all have done already.

jiblett1000 commented 1 year ago

Additionally, there is use for a TabsList component really as a standalone component. For example, it might be desirable to use the component in the layout of an app, which persists across route changes and allows changing the route either by customizing the TabTrigger components or through the @change event. This would render the TabContent and maybe even Tabs components useless in this scenario.

Again, this could very well be recreated, but it would be nice if the component was flexible enough to handle this and to benefit from the existing work/functionality (such as the TabIndicator).

cschroeter commented 1 year ago

From an accessibility standpoint tabs should not be used with out there counter parts (TabContent). We will offer a non tabconten version (segment control) that have the same benefits like tabs but not the restriction of having an associated tabcontent panel.

See https://park-ui.com/docs/components/segment-group for reference

jiblett1000 commented 1 year ago

@cschroeter I totally understand. I look forward to the new component. Sounds like a great solution. Thanks!