Design
Tabs
Simple Tab

Simple Tab

Implementing a simple tab component using Next.js and Tailwind CSS.

Preview

Tab 1 content

Installation

Install dependencies

pnpm add clsx tailwind-merge

Add util file

utils/cn.ts
import { type ClassValue, clsx } from "clsx";
import { twMerge } from "tailwind-merge";
 
export function cn(...inputs: ClassValue[]): string {
  return twMerge(clsx(inputs));
}

Copy the source code

components/ui/simpleTab.tsx
import React, { type Dispatch, type SetStateAction } from "react";
import { cn } from "@/util/cn";
 
interface TabProps {
  key?: string | number;
  children: string;
  currentVal: string;
  setCurrentVal: Dispatch<SetStateAction<string>>;
}
 
/**
 * Renders a tab component.
 *
 * @param children - The tab label.
 * @param currentVal - The current tab value.
 * @param setCurrentVal - The function to set the current tab value.
 * @returns  The rendered tab component.
 */
export function Tab({
  key,
  children,
  currentVal,
  setCurrentVal,
}: TabProps): React.JSX.Element {
  return (
    <button
      key={key}
      className={cn(currentVal === children ? "border-b border-b-blue-500" : "border-b border-b-transparent", "px-4 py-2")}
      onClick={() => {
        setCurrentVal(children);
      }}
      type="button"
    >
      {children}
    </button>
  );
}
 
export function TabContainer({
  children,
}: {
  children: React.ReactNode;
}): React.JSX.Element {
  return <div className="flex">{children}</div>;
}
 
interface ContentProps {
  currentVal: string;
  forTab: string;
  children: React.ReactNode;
}
/**
 * Renders the content for a tab.
 * @param currentVal - The current tab value.
 * @param forTab - The tab value for which the content is rendered.
 * @param children - The content to render.
 * @returns
 */
export function Content({
  currentVal,
  forTab,
  children,
}: ContentProps): React.JSX.Element {
  return <>{currentVal === forTab && children}</>;
}
 
export function ContentContainer({
  children,
}: {
  children:React.ReactNode;
}): React.JSX.Element {
  return <div className="mt-4">{children}</div>;
}

Use the component

"use client";
 
import React, { useState } from "react";
import { TabContainer, Tab, Content, ContentContainer } from "@/components/ui/simpleTab";
 
function SimpleTabDemo(): React.JSX.Element {
  const tabData: string[] = ["Tab 1", "Tab 2", "Tab 3"];
 
  const [currentVal, setCurrentVal] = useState<string>(tabData[0]);
 
  return (
    <div>
      <TabContainer>
        {
          tabData.map((tab) => {
            return (
              <Tab
                key={tab}
                currentVal={currentVal}
                setCurrentVal={setCurrentVal}
              >
                {tab}
              </Tab>
            );
          
          })
        }
      </TabContainer>
      <ContentContainer>
        <Content currentVal={currentVal} forTab={tabData[0]}>
          <div>Tab 1 content</div>
        </Content>
        <Content currentVal={currentVal} forTab={tabData[1]}>
          <div>Tab 2 content</div>
        </Content>
        <Content currentVal={currentVal} forTab={tabData[2]}>
          <div>Tab 3 content</div>
        </Content>
      </ContentContainer>
    </div>
  );
}
 
export default SimpleTabDemo;

File Structure of the project

        • simpleTab.tsx
      • cn.ts