Tabs are a common UI component that allow users to navigate between different views or sections of content. They can also be used to organize information into logical groups or categories. Here, provides a React component for creating tabs that are customizable, accessible, and easy to use. You can use this component to create tabs that switch content within the same page or route to different pages. This tab is styled using Tailwind CSS.
Folder Structure
src ├── app │ ├── page.js │ └── ... │── components │ ├── CustomTab │ └── ... ├── CustomTab.js │ ├── CustomTab.module.scss │ └── useCustomTab.js ├── styles │ └── main.scss │ └── ... ├── widgets └── ... └── TabSection └── ... └── index.js
app / page.js
import TabSection from "@/widgets/TabSection";
export default function Home() {
return (
<main>
<TabSection data={tabData} />
</main>
);
}
Here is an example data:
const tabData = [
{
tab_name: "Tab 1",
tab_control: {
action: "tab",
},
tab_contents: {
title: "Tab Content 1",
description:
"Ipsum minim aute exercitation occaecat nostrud fugiat nostrud. Non fugiat elit consequat sit aute dolor magna voluptate. Aliqua veniam irure aliqua nulla incididunt do laboris ex incididunt nostrud sunt occaecat eu. Ipsum minim aute exercitation occaecat nostrud fugiat nostrud. Non fugiat elit consequat sit aute dolor magna voluptate. Aliqua veniam irure aliqua nulla incididunt do laboris ex incididunt nostrud sunt occaecat eu.",
},
},
{
tab_name: "Tab 2",
tab_control: {
action: "tab",
},
tab_contents: {
title: "Tab Content 2",
description:
"In consequat magna ea excepteur ullamco voluptate velit dolor cillum proident. Magna proident consequat duis veniam do. Excepteur et ullamco incididunt labore sunt et consequat nulla adipisicing incididunt do veniam. Lorem incididunt duis veniam excepteur nulla irure esse nostrud irure mollit enim. Nostrud reprehenderit est incididunt nostrud ullamco mollit eu in ullamco cupidatat. Qui proident sint fugiat adipisicing. Ad aliquip non ea ipsum ea eu pariatur irure esse in eiusmod exercitation id.",
},
},
{
tab_name: "Tab 3 (Link)",
tab_control: {
action: "link",
url: "/link-3",
},
tab_contents: {
title: "Tab Content 3",
description:
"Ipsum fugiat fugiat elit nulla fugiat consequat ipsum incididunt amet aliquip ex qui ad dolor. Magna ad excepteur est occaecat incididunt ex esse eiusmod aliqua. Eiusmod occaecat dolore adipisicing ad culpa quis est do consequat excepteur cillum laborum do incididunt. Exercitation pariatur magna laborum proident. Cillum elit voluptate nostrud irure Lorem. Ipsum fugiat fugiat elit nulla fugiat consequat ipsum incididunt amet aliquip ex qui ad dolor. Magna ad excepteur est occaecat incididunt ex esse eiusmod aliqua.",
},
},
{
tab_name: "Tab 4 (Link)",
tab_control: {
action: "link",
url: "/link-4",
},
tab_contents: {
title: "Tab Content 4",
description:
"Magna ad excepteur est occaecat incididunt ex esse eiusmod aliqua. Eiusmod occaecat dolore adipisicing ad culpa quis est do consequat excepteur cillum laborum do incididunt. Exercitation pariatur magna laborum proident. Cillum elit voluptate nostrud irure Lorem. Ipsum fugiat fugiat elit nulla fugiat consequat ipsum incididunt amet aliquip ex qui ad dolor. Ipsum fugiat fugiat elit nulla fugiat consequat ipsum incididunt amet aliquip ex qui ad dolor. Magna ad excepteur est occaecat incididunt ex esse eiusmod aliqua.",
},
},
];
The Tab component is imported as below:
import { CustomTab } from "@/components/CustomTab/CustomTab";
widgets/TabSection/index.js
"use client";
import React from "react";
import { CustomTab } from "@/components/CustomTab/CustomTab";
const TabSection = ({ data }) => {
return (
<section className="min-h-[100vh] flex items-center">
<div className="container">
<CustomTab tabActive={`tab_item_000`}>
{data?.map((tab, tabIndex) => {
return (
<CustomTab.Tab
key={tabIndex}
tabId={`tab_item_${
tabIndex >= 10 ? "0" + tabIndex : "00" + tabIndex
}`}
tabTitle={tab?.tab_name}
tabControl={tab?.tab_control}
>
<h2 className="text-[28px] font-semibold mb-5">
{tab?.tab_contents?.title}
</h2>
<p className="text-[16px] font-regular">
{tab?.tab_contents?.description}
</p>
</CustomTab.Tab>
);
})}
</CustomTab>
</div>
</section>
);
};
export default TabSection;
components/CustomTab/CustomTab.js
import Link from "next/link";
import React, { Fragment } from "react";
import Style from "./CustomTab.module.scss";
import { useCustomTab } from "./useCustomTab";
const CustomTabItem = ({ children }) => {
return <div className={Style.Tab_card__content}>{children}</div>;
};
const CustomTab = ({ tabActive, children, ...props }) => {
const {
activeTabId,
navPosX,
navWidth,
activeTabRef,
tabItemRef,
handleTabChange,
} = useCustomTab({ tabActive, props });
return (
<div className={Style.tab_card}>
<div className="flex justify-between">
<nav
className={`${Style.tab_card__nav} flex gap-x-9 relative text-[var(--tab-nav-color)] w-full overflow-auto`}
style={{
"--nav-floater-width": `${navWidth}px`,
"--nav-floater-x": `${navPosX}px`,
}}
>
{children?.length > 0 ? (
<>
{children?.map((tab, i) => {
return (
<Fragment key={i}>
{tab?.props?.tabControl?.action === "tab" ? (
<button
key={i}
onClick={(e) => handleTabChange(e, tab?.props?.tabId)}
id={tab?.props?.tabId}
className={`${Style.nav_item ?? "nav-item"} ${
tab?.props?.tabId === activeTabId ? Style.active : ""
} pb-3 text-[14px] lg:text-[18px] leading-[35px] font-normal whitespace-nowrap`}
ref={
tab?.props?.tabId === activeTabId
? activeTabRef
: tabItemRef
}
>
{tab?.props?.tabTitle}
</button>
) : tab?.props?.tabControl?.action === "link" ? (
<Link
href={`${tab?.props?.tabControl?.url}`}
className={`${Style.nav_item ?? "nav-item"} ${
tab?.props?.tabId === activeTabId ? Style.active : ""
} no-decoration d-flex align-items-center pb-3 text-[14px] lg:text-[18px] leading-[35px] font-normal whitespace-nowrap`}
>
{tab?.props?.tabTitle}
</Link>
) : (
""
)}
</Fragment>
);
})}
</>
) : (
<div className={`${Style.nav_item} text-dark`}>
{children?.props?.tabTitle}
</div>
)}
<div
className={`${
Style.nav_floater ?? "nav-floater"
} absolute bottom-0 h-[2px] bg-[var(--tab-nav-color)] w-[var(--nav-floater-width)] left-[var(--nav-floater-x)] transition-all ease-in-out duration-300`}
/>
</nav>
</div>
<div
className={`${
Style.tab_card__body ?? "tab-card__body"
} relative pt-[var(--tab-content-pt)]`}
>
{!children?.length > 0
? children
: children.filter((child) => child?.props?.tabId === activeTabId)}
</div>
</div>
);
};
export { CustomTabItem, CustomTab };
CustomTab.Tab = CustomTabItem;
components/CustomTab/useCustomTab.js
import { useEffect, useRef, useState } from "react";
export const useCustomTab = ({ tabActive, props }) => {
const [activeTabId, setActiveTabId] = useState(tabActive);
const [navPosX, setNavPosX] = useState(0);
const [navWidth, setNavWidth] = useState(0);
const activeTabRef = useRef();
const tabItemRef = useRef();
useEffect(() => {
setNavPosX(activeTabRef?.current?.offsetLeft);
setNavWidth(activeTabRef?.current?.clientWidth);
}, []);
const handleTabChange = (e, activeTab) => {
let { offsetLeft, offsetWidth } = e.target;
setNavPosX(offsetLeft);
setNavWidth(offsetWidth);
setActiveTabId(activeTab);
props?.onTabChangeData && props?.onTabChangeData(activeTab);
e.target.scrollIntoView({
behavior: "smooth",
block: "start",
inline: "center",
});
};
return {
activeTabId,
setActiveTabId,
navPosX,
setNavPosX,
navWidth,
setNavWidth,
activeTabRef,
tabItemRef,
handleTabChange,
};
};
components/CustomTab/CustomTab.module.scss
.tab_card {
&__nav {
scrollbar-width: none;
&::-webkit-scrollbar {
display: none;
}
.nav_item {
&.active {
@apply font-semibold;
text-shadow: 0 0 0.3px var(--tab-nav-color),
0 0 0.3px var(--tab-nav-color);
}
}
}
}
styles/main.scss
@tailwind base;
@tailwind components;
@tailwind utilities;
:root {
--tab-nav-color: #000;
--tab-content-pt: 62px;
}
Props
- tabId: A unique identifier for each tab item. This prop is required and should be a string.
- tabActive: Tab Id of the active tab item.
- tabTitle: The title for each tab nav item. This prop is required and should be a string.
- tabControl: The type of control for each tab item. This prop is required and can be either
"tab"or"link". If you set this prop to"tab", the tab item will switch the content within the same page. If you set this prop to"link", the tab item will route to another page using thehrefattribute. You can use this prop to create different types of tabs depending on your needs.
Top comments