Componenteditors1.11 KB gzipZero dependencies
Code Tabs
Multi-language code block with tabs and copy.
Preview
Live Preview
npm install bigbulluiInstallation
Tokens guide →Add to your project via CLI (zero dependencies, code you own):
npx bigbullui add code-tabsOr install the full npm package:
npm install bigbulluiUsage
Open in StackBlitzimport { CodeTabs } from "@/components/ui/code-tabs";
<CodeTabs tabs={[{ id: "npm", label: "npm", code: "npm install bigbullui" }]} />Usage guidance
Use Code Tabs when a ticket stub surface needs Multi-language code block with tabs and copy. Keep props minimal and prefer composition with sibling stubs.
Avoid Code Tabs for long form flows or dense data grids where a dedicated layout block fits better.
Source code
code-tabs.tsxZero dependencies (only React + utils). Copy and paste directly into your project:
"use client";
import * as React from "react";
import { cn } from "./lib/utils";
export interface CodeTabsTab {
id: string;
label: string;
code: string;
language?: string;
}
export interface CodeTabsProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "onCopy"> {
tabs: CodeTabsTab[];
defaultTab?: string;
onCopy?: (code: string, tabId: string) => void;
}
export function CodeTabs({ tabs, defaultTab, onCopy, className, ...props }: CodeTabsProps) {
const [active, setActive] = React.useState(defaultTab ?? tabs[0]?.id ?? "");
const [copied, setCopied] = React.useState(false);
const current = tabs.find((t) => t.id === active) ?? tabs[0];
const copy = async () => {
if (!current) return;
try {
await navigator.clipboard.writeText(current.code);
} catch {
/* clipboard unavailable */
}
onCopy?.(current.code, current.id);
setCopied(true);
setTimeout(() => setCopied(false), 1600);
};
if (!current) {
return <div className={cn("w-full", className)} {...props} />;
}
return (
<div className={cn("w-full overflow-hidden rounded-lg border border-border bg-card", className)} {...props}>
<div className="flex items-center justify-between gap-2 border-b border-dashed border-border px-2 pt-2">
<div role="tablist" aria-label="Code variants" className="flex flex-wrap gap-1">
{tabs.map((t) => (
<button
key={t.id}
type="button"
role="tab"
aria-selected={t.id === active}
onClick={() => setActive(t.id)}
className={cn(
"cursor-pointer rounded-t-md border border-b-0 px-3 py-1.5 font-mono text-xs transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
t.id === active
? "border-border bg-secondary font-bold"
: "border-transparent text-muted-foreground hover:text-foreground",
)}
>
{t.label}
</button>
))}
</div>
<button
type="button"
onClick={copy}
className="mb-1 shrink-0 cursor-pointer rounded border border-border px-2 py-1 font-mono text-[10px] uppercase transition-colors hover:border-foreground"
>
{copied ? "Copied" : "Copy"}
</button>
</div>
<pre className="overflow-x-auto p-4 font-mono text-xs leading-relaxed">
<code>
{current.code.split("\n").map((line, i) => (
<span key={i} className="block">
<span aria-hidden className="mr-3 inline-block w-6 select-none text-right text-muted-foreground/50">
{i + 1}
</span>
{line || " "}
</span>
))}
</code>
</pre>
</div>
);
}
Props
| Prop | Type | Description |
|---|---|---|
| tabs | CodeTabsTab[] | Tabs with id, label, code (required). |
| defaultTab | string | Initial tab id. |
| onCopy | (code: string, tabId: string) => void | Copy callback. |