Mohammad Shehadeh

Terminal

Component

About

Terminal surface with a title bar, output lines and an interactive prompt input with command-history recall. Ships composable parts.

Built with React and Tailwind. Copy the prompt and paste it into Claude Code, Cursor or Lovable: your agent adds Terminal to your project and fits it to your theme.

Code

How Terminal is used: the demo's code. The component's own source comes with a free account.

Usage.tsx

"use client";

import * as React from "react";
import {
  Terminal,
  TerminalHeader,
  TerminalBody,
  TerminalLine,
  TerminalPrompt,
  TerminalInput,
} from "@/components/ui/terminal";

interface TerminalEntry {
  kind: "command" | "output" | "error";
  text: string;
}

const TERMINAL_USER = "deploy@edge";

export default function TerminalDemo() {
  const [entries, setEntries] = React.useState<TerminalEntry[]>([
    { kind: "output", text: "Hirael cloud shell. Type `help` to start" },
    { kind: "command", text: "status" },
    { kind: "output", text: "api  ok    worker  ok    db  degraded" },
  ]);

  function run(command: string) {
    const next: TerminalEntry[] = [{ kind: "command", text: command }];
    const [name, ...args] = command.split(/\s+/);

    switch (name) {
      case "help":
        next.push({
          kind: "output",
          text: "commands: help  ls  status  whoami  echo  clear",
        });
        break;
      case "ls":
        next.push({
          kind: "output",
          text: "services/  infra/  README.md  deploy.sh",
        });
        break;
      case "status":
        next.push({
          kind: "output",
          text: "api  ok    worker  ok    db  degraded",
        });
        break;
      case "whoami":
        next.push({ kind: "output", text: TERMINAL_USER });
        break;
      case "echo":
        next.push({ kind: "output", text: args.join(" ") });
        break;
      case "clear":
        setEntries([]);
        return;
      default:
        next.push({ kind: "error", text: `command not found: ${name}` });
    }

    setEntries((prev) => [...prev, ...next]);
  }

  return (
    <section className="flex w-full justify-center bg-background p-6 sm:p-10">
      <div className="w-full max-w-2xl">
        <Terminal>
          <TerminalHeader>{TERMINAL_USER}: ~/app</TerminalHeader>
          <TerminalBody>
            {entries.map((entry, i) => {
              if (entry.kind === "command") {
                return (
                  <TerminalLine key={i}>
                    <TerminalPrompt>{TERMINAL_USER}</TerminalPrompt>
                    {entry.text}
                  </TerminalLine>
                );
              }
              return (
                <TerminalLine
                  key={i}
                  className={
                    entry.kind === "error"
                      ? "text-destructive"
                      : "text-muted-foreground"
                  }
                >
                  {entry.text}
                </TerminalLine>
              );
            })}
            <TerminalInput
              user={TERMINAL_USER}
              onSubmit={run}
              aria-label="Terminal command"
            />
          </TerminalBody>
        </Terminal>
      </div>
    </section>
  );
}

More by Mohammad Shehadeh

View all
  • Feature Problem Cards

    Feature Problem Cards

    84
  • Feature Grid Spotlight Cards

    Feature Grid Spotlight Cards

    69
  • Dithered Shader CTA

    Dithered Shader CTA

    63
  • Split Login

    Split Login

    60
  • FAQ Two Column

    FAQ Two Column

    59
  • Comparison Table

    Comparison Table

    58
  • Ecommerce Category Page

    Ecommerce Category Page

    57
  • Comparison Section

    Comparison Section

    56

Explore more

Part of Hirael — browse the full library on 21st.dev.