Skip to content

Commit d6168f5

Browse files
authored
Merge pull request #4 from num-js/component-tabs
Added new component - 'Tabs' component with documentation
2 parents 9d31062 + d03b0e8 commit d6168f5

4 files changed

Lines changed: 117 additions & 1 deletion

File tree

configs/componentsDocumentation.json

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,20 @@
138138
"type": "image-hover",
139139
"new": true
140140
},
141+
{
142+
"name": "Tabs",
143+
"componentArray": [
144+
{
145+
"componentName": "tabs",
146+
"filesrc": "components/tabs/tabs.tsx",
147+
"iframeSrc": "live-components/tabs",
148+
"parentlink": "tabs",
149+
"parentName": "Tabs"
150+
}
151+
],
152+
"type": "tabs",
153+
"new": true
154+
},
141155
{
142156
"name": "Footers",
143157
"componentArray": [

configs/leftSideComponentMetaData.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,12 @@ export const basicComponents = [
2121
{
2222
href: '/components/image-hover',
2323
name: 'Image Hover',
24-
component: 'image-hover',
24+
component: 'image-hover'
25+
},
26+
{
27+
href: '/components/tabs',
28+
name: 'Tabs',
29+
component: 'tabs',
2530
new: true,
2631
},
2732
{

content/components/tabs.mdx

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
export const metadata = {
2+
title: "Tabs - Animated Sliding Pill Tabs Component",
3+
description: "A modern, accessible React tabs component with smooth sliding pill indicator. Features animated transitions, dark mode support, and mobile-responsive design. Perfect for dashboard navigation, settings panels, and content organization with elegant hover effects and seamless tab switching.",
4+
keywords: [
5+
"Tabs React",
6+
"Animated Tabs React",
7+
"Moving indicator tabs",
8+
"Vercel style tabs",
9+
"Sliding pill indicator",
10+
"Active tab background",
11+
"Tabs with animation",
12+
"React animated navigation",
13+
"tab highlight",
14+
"Smooth tab transition",
15+
"UI tabs component",
16+
"Hover/active tab animation",
17+
"Accessible tabs React",
18+
"Interactive tab switcher",
19+
"Modern tabs UI",
20+
"Dark mode tabs",
21+
"Tailwind CSS tabs",
22+
"Pill navigation",
23+
"Settings navigation tabs",
24+
"Content switcher component",
25+
],
26+
authors: [{ name: "Numan", url: "https://numan-dev.web.app" }],
27+
creator: "@numan-dev",
28+
publisher: "Struct-UI",
29+
robots: {
30+
index: true,
31+
follow: true,
32+
googleBot: {
33+
index: true,
34+
follow: true,
35+
"max-video-preview": -1,
36+
"max-image-preview": "large",
37+
"max-snippet": -1
38+
}
39+
},
40+
category: "technology"
41+
};
42+
43+
<ComponentCodePreview name='tabs' hasReTrigger isFitheight />

registry/components/tabs/tabs.tsx

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
'use client';
2+
import { useState } from 'react';
3+
4+
interface ITabs {
5+
label: string;
6+
id: string;
7+
}
8+
9+
export default function Tabs() {
10+
const [selectedTab, setSelectedTab] = useState<string>('tab1');
11+
12+
const tabsConfig: ITabs[] = [
13+
{ label: 'Tab 1', id: 'tab1' },
14+
{ label: 'Tab 2', id: 'tab2' },
15+
{ label: 'Tab 3', id: 'tab3' },
16+
];
17+
18+
const selectedIndex = tabsConfig.findIndex(section => section.id === selectedTab);
19+
const sliderWidth = 100 / tabsConfig.length;
20+
21+
const handleTabChange = (sectionId: string) => {
22+
setSelectedTab(sectionId);
23+
};
24+
25+
return (
26+
<section className="w-full max-w-screen-sm mx-auto p-2">
27+
<div className="relative flex bg-gray-200 dark:bg-gray-900 rounded-full p-1 shadow-inner dark:shadow-gray-950">
28+
<div className="relative flex bg-gray-100 dark:bg-gray-800 rounded-full p-1 shadow-inner dark:shadow-gray-900 min-w-[200px] w-full">
29+
<div
30+
className="absolute top-1 h-[calc(100%-8px)] bg-white dark:bg-gray-700 rounded-full shadow-md dark:shadow-black/30 transition-all duration-300 ease-in-out z-10"
31+
style={{
32+
width: `calc(${sliderWidth}% - 8px)`,
33+
left: `calc(${selectedIndex * sliderWidth}% + 4px)`,
34+
}}
35+
/>
36+
{tabsConfig.map((tab) => (
37+
<button
38+
key={tab.id}
39+
className={`relative z-20 flex-1 bg-transparent border-none font-medium rounded-full transition-all duration-300 py-2 px-4 ${
40+
selectedTab === tab.id
41+
? 'text-black dark:text-white font-semibold'
42+
: 'text-gray-700 dark:text-gray-400 hover:bg-gray-300 dark:hover:bg-gray-700'
43+
}`}
44+
onClick={() => handleTabChange(tab.id)}
45+
disabled={selectedTab === tab.id}
46+
>
47+
{tab.label}
48+
</button>
49+
))}
50+
</div>
51+
</div>
52+
</section>
53+
);
54+
}

0 commit comments

Comments
 (0)