Code block with copy-to-clipboard button
Install
npx shadcn add https://ui.happenings.social/r/code-block.json
Or with namespace
npx shadcn add @happenings/code-block
Preview
Dependencies
src/components/ui/code-block.tsx
"use client";
import * as React from "react";
import { faCopy, faCheck } from "@fortawesome/pro-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { cn } from "@/lib/utils";
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from "./tooltip";
interface CodeBlockProps {
code: string;
label?: string;
className?: string;
copyLabel?: string;
copiedLabel?: string;
}
function CodeBlock({
code,
label,
className,
copyLabel = "Copy",
copiedLabel = "Copied!",
}: CodeBlockProps) {
const [copied, setCopied] = React.useState(false);
const handleCopy = React.useCallback(() => {
navigator.clipboard.writeText(code);
setCopied(true);
setTimeout(() => setCopied(false), 2000);
}, [code]);
return (
<div className={cn("group relative", className)}>
{label && (
<p className="mb-1.5 text-xs font-medium text-muted-foreground">
{label}
</p>
)}
<div className="relative overflow-hidden rounded-lg border border-border bg-white dark:bg-input/30">
<pre className="overflow-x-auto p-3 pr-12 font-mono text-[13px] leading-relaxed text-foreground">
{code}
</pre>
<TooltipProvider delayDuration={300}>
<Tooltip>
<TooltipTrigger asChild>
<button
type="button"
onClick={handleCopy}
className="absolute right-2 top-2 inline-flex h-7 w-7 cursor-pointer items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-accent hover:text-foreground"
aria-label={copied ? copiedLabel : copyLabel}
>
<FontAwesomeIcon
icon={copied ? faCheck : faCopy}
className={cn(
"size-3 transition-colors",
copied && "text-emerald-500",
)}
/>
</button>
</TooltipTrigger>
<TooltipContent>
{copied ? copiedLabel : copyLabel}
</TooltipContent>
</Tooltip>
</TooltipProvider>
</div>
</div>
);
}
export { CodeBlock };
export type { CodeBlockProps };
Preview
Install
npm install @happenings/ui
npx shadcn add @happenings/button