Tabs

tabs

Tabbed panels swapping content without route changes.

It is a React component (often forwardRef) styled with Tailwind utility classes so you can drop it into layouts or compose it with other kit pieces.

blogs/components/tabs/Tabs.tsx

Preview

Tab A content

Tab B content

Source

import React, { useState } from "react";

export interface TabItem {
  id: string;
  label: React.ReactNode;
  badge?: React.ReactNode;
  content: React.ReactNode;
}

export interface TabsProps {
  tabs: TabItem[];
  defaultTab?: string;
}

export const Tabs: React.FC<TabsProps> = ({ tabs, defaultTab }) => {
  const [active, setActive] = useState(defaultTab || tabs?.[0]?.id);

  return (
    <div>
      <div className="flex gap-0 border-b border-zinc-200 mb-4 overflow-x-auto scrollbar-none">
        {tabs?.map((tab) => (
          <button
            key={tab.id}
            onClick={() => setActive(tab.id)}
            className={`flex items-center gap-1.5 px-4 py-2 text-sm border-b-2 -mb-px transition-all whitespace-nowrap cursor-pointer ${
              active === tab.id
                ? "border-zinc-900 text-zinc-900 font-medium"
                : "border-transparent text-zinc-500 hover:text-zinc-800"
            }`}
          >
            {tab.label}
            {tab.badge && (
              <span className="ml-1.5 inline-flex items-center justify-center rounded-full bg-blue-100 px-1.5 py-0.5 text-[10px] font-medium text-blue-700">
                {tab.badge}
              </span>
            )}
          </button>
        ))}
      </div>
      {tabs?.map((tab) => (
        <div
          key={tab.id}
          style={{ display: active === tab.id ? "block" : "none" }}
        >
          {tab.content}
        </div>
      ))}
    </div>
  );
};