Large uppercase tabs on the left with the open tab's heading, text and highlighted stats on the right. React and Tailwind CSS, accessible tablist.
DarkFeatureTabs.tsx
"use client";
// Dark feature tabs: large uppercase tab labels on the left, the open tab's
// heading, text and stats on the right. Accessible tablist.
// Pure Tailwind + React, no dependencies. Works with Tailwind v3 and v4.
import { useState } from "react";
type Tab = { label: string; heading: string; text: string; stats: { value: string; label: string }[] };
type Props = {
tabs?: Tab[];
};
const DEFAULT_TABS: Tab[] = [
{ label: "Range", heading: "Go further on a single charge", text: "A 98 kWh battery and an efficient drivetrain take you city to coast without a stop.", stats: [{ value: "610 km", label: "WLTP range" }, { value: "18 min", label: "10–80% charge" }] },
{ label: "Power", heading: "Instant, effortless torque", text: "Dual motors deliver smooth power from standstill and confident overtaking at speed.", stats: [{ value: "523 hp", label: "Combined output" }, { value: "3.9 s", label: "0–100 km/h" }] },
{ label: "Comfort", heading: "Quiet, calm and roomy", text: "Acoustic glass, adaptive air suspension and heated seats in every row.", stats: [{ value: "7", label: "Seats" }, { value: "780 L", label: "Boot space" }] },
];
export default function FeatureTabs({ tabs = DEFAULT_TABS }: Props) {
const [active, setActive] = useState(0);
const tab = tabs[active];
if (!tab) return null;
return (
<section className="bg-[#1f1f1d] px-4 py-20 font-['Inter',ui-sans-serif,system-ui,sans-serif] text-white antialiased md:px-8 md:py-36">
<div className="mx-auto grid max-w-5xl gap-12 md:grid-cols-2 md:gap-8">
<div role="tablist" aria-label="Features" className="max-w-[25rem]">
{tabs.map((t, i) => (
<button
key={t.label}
id={`feature-tab-${i}`}
type="button"
role="tab"
aria-selected={i === active}
aria-controls={`feature-panel-${i}`}
onClick={() => setActive(i)}
className={`flex h-20 w-full items-center border-b border-white/30 text-left font-['Prompt',ui-sans-serif,system-ui,sans-serif] text-4xl uppercase transition-all duration-300 md:h-32 md:text-6xl ${
i === active ? "pl-12 text-white" : "text-white/30 hover:text-white/60"
}`}
>
{t.label}
</button>
))}
</div>
<div id={`feature-panel-${active}`} role="tabpanel" aria-labelledby={`feature-tab-${active}`}>
<h2 className="font-['Prompt',ui-sans-serif,system-ui,sans-serif] text-3xl font-semibold uppercase md:text-4xl">{tab.heading}</h2>
<p className="mt-5 text-white/80">{tab.text}</p>
<dl className="mt-10 grid grid-cols-[auto_1fr] gap-x-8 gap-y-8">
{tab.stats.map((stat) => (
<div key={stat.label} className="flex min-w-[9rem] flex-col-reverse gap-1">
<dt className="text-lg text-white/70">{stat.label}</dt>
<dd className="font-['Prompt',ui-sans-serif,system-ui,sans-serif] text-3xl font-semibold text-[#ffdc2a] md:text-4xl">{stat.value}</dd>
</div>
))}
</dl>
</div>
</div>
</section>
);
}
How to use it
- Make sure your Next.js or React project has Tailwind CSS set up (v3 or v4 both work).
- Create
components/DarkFeatureTabs.tsxand paste the code. - Import it into a page and replace the sample text and images with your own.
