Components / Others
Terminal Log
Free Others React component — TerminalLogCard. MIT licensed, copy-paste ready for Next.js and Tailwind CSS.
macOS terminal window with traffic-light dots, colored log lines, blinking cursor, and status footer. Dev tool aesthetic for changelogs or demos.
Preview
~ npx appui add metric-card
Resolving dependencies...
✓ Copied MetricCard.tsx
✓ Updated tailwind.config
Done in 1.8s
~
Setup
How to use
Free for personal and commercial use. No UI attribution required. Include the MIT copyright notice when copying component source into your project. Read the MIT license.
- 1
Run in your terminal:
$npm install clsx tailwind-merge lucide-react - 2
Copy
lib/cn.tsbelow. Skip if you already havecn(). - 3
Copy the code below and create
components/others/terminal-log-card.tsxin your project. - 4
Import and render:
Exampleimport { TerminalLogCard } from "@/components/others/terminal-log-card";
lib/cn.ts
import { type ClassValue, clsx } from "clsx";import { twMerge } from "tailwind-merge";export function cn(...inputs: ClassValue[]) {return twMerge(clsx(inputs));}
components/others/terminal-log-card.tsx
"use client";import { forwardRef, type ComponentPropsWithoutRef } from "react";import { cn } from "@/lib/cn";import { Command } from "lucide-react";export type TerminalLogLine = {type: "cmd" | "out" | "ok" | "err";text: string;};export type TerminalLogCardProps = Readonly<{title?: string;prompt?: string;lines?: TerminalLogLine[];status?: string;} & ComponentPropsWithoutRef<"div">>;const defaultLines: TerminalLogLine[] = [{ type: "cmd", text: "npx appui add metric-card" },{ type: "out", text: "Resolving dependencies..." },{ type: "ok", text: "✓ Copied MetricCard.tsx" },{ type: "ok", text: "✓ Updated tailwind.config" },{ type: "out", text: "Done in 1.8s" },];const lineColors: Record<TerminalLogLine["type"], string> = {cmd: "text-emerald-400",out: "text-neutral-500",ok: "text-sky-400",err: "text-rose-400",};// Production-ready Terminal Log component — styled with Tailwind CSS.export const TerminalLogCard = forwardRef<HTMLDivElement, TerminalLogCardProps>(({className,title = "appui — zsh",prompt = "~",lines = defaultLines,status = "ready",...props},ref,) => (<divref={ref}data-slot="terminal-log-card"className={cn("w-sm overflow-hidden rounded-xl border border-neutral-800 bg-[#0d0d0d] font-mono text-[11px] shadow-2xl shadow-black/40 sm:max-w-xs",className,)}{...props}><divdata-slot="terminal-log-card-header"className="flex items-center gap-2 border-b border-neutral-800 px-3 py-2"><div className="flex gap-1.5"><span className="h-2.5 w-2.5 rounded-full bg-[#ff5f57]" /><span className="h-2.5 w-2.5 rounded-full bg-[#febc2e]" /><span className="h-2.5 w-2.5 rounded-full bg-[#28c840]" /></div><span className="flex-1 truncate text-center text-[10px] text-neutral-600">{title}</span><Command size={10} className="text-neutral-700" /></div><divdata-slot="terminal-log-card-body"className="space-y-1 px-3 py-3 leading-relaxed">{lines.map((line) => (<pkey={`${line.type}-${line.text}`}data-slot="terminal-log-card-line"className={cn("break-all", lineColors[line.type])}>{line.type === "cmd" && (<span className="text-neutral-600">{prompt} </span>)}{line.text}</p>))}<p className="text-neutral-600"><span className="text-emerald-500">{prompt}</span><span className="ml-1 inline-block h-3 w-1.5 animate-pulse bg-emerald-400" /></p></div><divdata-slot="terminal-log-card-footer"className="border-t border-neutral-800/80 px-3 py-1.5 text-[9px] text-neutral-600">{status}</div></div>),);TerminalLogCard.displayName = "TerminalLogCard";