I'm trying to create a reusable Tabs component with headless ui (https://headlessui.com/react/tabs) that works with react router
Here is a minimal reproducible example, clicking on a tab takes you to a new page when it should be changing the tab panel and keeping the actual tabs visible on the page, what am I missing?: https://codesandbox.io/s/3ogj23?file=/src/Components/TestComponents/TestComponents.tsx (edit - question resolved, thank you Drew Reese, working sandbox here)
This is the reusable component so far:
export interface TabData {
route: string;
label: string;
component: React.ReactElement;
}
export interface TabProps {
tabInfo: TabData[];
onTabChange: (selectedIndex: number) => void;
}
function Tabs({ tabInfo, onTabChange }: TabProps) {
const [selectedIndex, setSelectedIndex] = useState<number>(0);
return (
<div>
<Tab.Group
selectedIndex={selectedIndex}
onChange={(selectedTabIndex: number) => {
setSelectedIndex(selectedTabIndex);
onTabChange(selectedTabIndex);
}}
>
<Tab.List
---styling removed----
>
{tabInfo.map((item, index) => (
<Tab
key={index}
aria-label={`${item.label}`}
name={`${item.label}`}
---styling removed----
>
{item.label}
</Tab>
))}
</Tab.List>
<Tab.Panels>
{tabInfo.map((item, index) => (
<Tab.Panel key={index} className="bg-white p-4">
<div>{item.component}</div>
</Tab.Panel>
))}
</Tab.Panels>
</Tab.Group>
</div>
);
}
export default Tabs;
And this is a snippet where I am implementing it in another component:
import { useNavigate } from 'react-router-dom';
----other code-------
const navigate = useNavigate();
return (
----other code-------
const handleOnTabChange = (selectedIndex: number) => {
const path = TabsData[selectedIndex].route;
navigate(`/${path}`, {
// not sure this is needed
state: { tab: selectedIndex },
replace: false,
});
};
---irrelevent code removed---
<Tabs tabInfo={TabsData} onTabChange={(selectedIndex) => handleOnTabChange(selectedIndex)} marginWidth={45} />
So basically, the reusable component returns the index of the selected tab so I can use that info to select the route I want from a an array (provided on implementation) like this:
export const TabsData = [
{
route: '',
label: 'Tab 1',
component: <Component1 />,
},
{
route: 'tab-2-route',
label: 'Tab 2',
component: <Component2 />,
},
{
route: 'tab-3-route',
label: 'Tab 3',
component: <Component3 />,
},
{
route: 'tab-4-route',
label: 'Tab 4',
component: <Component4 />,
},
];
This works in so far as I get the required path however, when i click on each individual tab I'm taken to the required component in a new browser window not the tab panel
How do I amend my reusable component or my implementation so that when I click on the required tab I get the component in the tab panel rather than a new page?