Doist/reactist

Tabs: Expose easier way to access current tab id.

scottlovegrove opened this issue · 5 comments

🚀 Feature request (I think)

Motivation

Using the new tabs components, I still found myself needing to know what the currently selected tab id was. I know under the hood these components are using the Reakit tabs, and that does offer access to that via the useTabState hook, but this isn't available (I don't think) when using the Reactist tabs.

Example

What I've ended up having to do is work around it like this

const [selectedTab, setSelectedTab] = useState<string>('book-now')
...

function setTabId(selectedId?: string | null) {
    if (selectedId) {
        setSelectedTab(selectedId)
    }
}
...
<Tabs>
    <TabList aria-hidden={true} space="medium">
        <Tab id="book-now">Now booking</Tab>
        <Tab id="coming-soon">Coming soon</Tab>
    </TabList>
    <TabAwareSlot>{({ selectedId }) => <>{setTabId(selectedId)}</>}</TabAwareSlot>
    <TabPanel id="book-now">
        <FilmViewer />
    </TabPanel>

    <TabPanel render="lazy" id="coming-soon">
        <ComingSoon />
    </TabPanel>
</Tabs>

Having the TabAwareSlot is fine for if you're wanting to display something in the UI, but it's not ideal if you just need the tab id.

Possible implementations

I think maybe exposing the useTabState() hook could help remedy this, or a Reactist variant of this hook.

Interesting…

I wonder if you can expand a bit more on why do you have the need to know it outside the tabs UI? Before adding new APIs I'd rather dig deeper on the supposed need for it.

I wonder if you can expand a bit more on why do you have the need to know it outside the tabs UI?

Sure. So I have the following page in my app
image

The user can be on "Now booking" or "Coming soon", the user can then click the refresh button at the bottom; this is part of the same page, so it would need to know for which tab it's refreshing the data.

I can imagine ways to overcome that situation without changing our API, and I was about to propose some ideas, but I realize that they all make assumptions about how you manage the state in those listings, and it could all make you have to find workarounds. I can understand, for instance, how you could be handling all your data right in the body of the component that renders the entire Tabs UI. And that's totally acceptable. Recommended, even, for smaller apps.

So yes, we could/should explore a way to make the Tabs component be controlled (). That is, to allow the consumer of that component to own the selected tab state management. So we could use the tabs in two different ways:

Uncontrolled

What we have today

<Tabs>
  {/* tabs and tabs panels inside */}
</Tabs>

Controlled

const [selectedTab, setSelectedTab] = React.useState('initial-state')

return (
  <Tabs selectedTab={selectedTab} onChange={setSelectedTab}>
    {/* tabs and tabs panels inside */}
  </Tabs>
)

So yes, we could/should explore a way to make the Tabs component be controlled (). That is, to allow the consumer of that component to own the selected tab state management.

That works for me 👍🏻

@scottlovegrove FYI, you can now use the tabs as a controlled component using the selectedId and onSelectedIdChange props. This was introduced with #662