This is an idea to implement tabs with React Router (v6) and styled-components. (demo)
Overview
Use React Router to switch panels
Use React Router NavLink as a Tab
Each panel is a Route whose element is TabPanel
Tabs
Tabs.tsx
import React from "react";
import { TabContainer, TabPanelContainer } from "./Tabs.styles";
import { TabListType } from "../../data/tab-lists";
import TabList from "../TabList/TabList";
type TabsProps = {
children: JSX.Element;
tabLists: TabListType[];
};
const Tabs = ({ children, tabLists }: TabsProps) => {
return (
<TabContainer>
<TabList tabLists={tabLists} />
<TabPanelContainer>{children}</TabPanelContainer>
</TabContainer>
);
};
export default Tabs;
Tabs.styles.tsx
import styled from "styled-components";
type TabPanelProps = {
height?: string;
};
export const TabContainer = styled.div`
display: grid;
grid-template-columns: 120px auto;
`;
export const TabPanelContainer = styled.div`
overflow-y: scroll;
height: ${({ height = "100vh" }: TabPanelProps) => height};
`;
TabList
TabList.tsx
import React from "react";
import { TabListType } from "../../data/tab-lists";
import { TabListContainer, StyledNavLink } from "./TabList.styles";
type TabListProps = {
tabLists: TabListType[];
};
const TabList = ({ tabLists }: TabListProps) => {
return (
<TabListContainer>
{tabLists.map((TabList) => (
<StyledNavLink key={TabList.tabKey} to={TabList.tabKey}>
{TabList.title}
</StyledNavLink>
))}
</TabListContainer>
);
};
export default TabList;
TabList.styles.tsx
I made use of the default active class to style the active navigation state. (ref: https://reactrouter.com/en/main/components/nav-link#default-active-class)
import styled from "styled-components";
import { NavLink } from "react-router-dom";
type TabListContainerProps = {
height?: string;
};
export const TabListContainer = styled.div`
display: flex;
flex-direction: column;
overflow-y: scroll;
height: ${({ height = "100vh" }: TabListContainerProps) => height};
`;
export const StyledNavLink = styled(NavLink)`
display: block;
color: black;
text-transform: capitalize;
text-align: center;
text-decoration: none;
padding: 5px;
background-color: #efefef;
&.active {
border-left: 3px solid black;
background-color: white;
}
`;
TabPanel
TabPanel.tsx
import React from "react";
import { TabPanelContainer } from "./TabPanel.styles";
type TabPanelProps = {
title: string;
};
const TabPanel = ({ title }: TabPanelProps) => {
return (
<TabPanelContainer>
<h1>{title}</h1>
</TabPanelContainer>
);
};
export default TabPanel;
TabPanel.styles.tsx
import styled from "styled-components";
export const TabPanelContainer = styled.div`
padding: 10px;
`;
App.tsx
import "./styles.css";
import { Routes, Route, Navigate } from "react-router-dom";
import Tabs from "./components/Tabs/Tabs";
import TabPanel from "./components/TabPanel/TabPanel";
import { tabLists } from "./data/tab-lists";
export default function App() {
return (
<Tabs tabLists={tabLists}>
<Routes>
{tabLists.map((tabList) => (
<Route
key={tabList.tabKey}
path={tabList.tabKey}
element={<TabPanel title={tabList.title} />}
/>
))}
<Route path="*" element={<Navigate to="home" />} />
</Routes>
</Tabs>
);
}
That’s it!
As a side note, I created the mock tabList with chatGPT.
The entire code is available here.
The original article is here
Top comments (0)