# Terminal

- Page: <https://kznlabs.github.io/labsUI/components/terminal>

## Terminal (`terminal`, component)

Terminal window. Snippet mode types install commands once scrolled into view, with the full transcript kept in the DOM for SEO and no-JS; log mode streams lines into a live region that follows the bottom unless you scroll up, then offers a jump back. Status lines carry glyphs, copy grabs the commands.

- Install: `npx @kznlabs/labsui add terminal`
- Docs: <https://kznlabs.github.io/labsUI/components/terminal>
- Brings: app-window, button, button-variants, code, highlight, list, overflow-focus, platform, tabs, tooltip, use-anchor, use-controllable-state, use-dismiss, use-hover-open, use-indicator, utils
- npm: clsx@^2.1.1, lucide-react@1.63.0, motion@14.7.1, prettier@^3.9.10, shiki@^4.5.0, tailwind-merge@^3.7.0

### API

- `<Terminal>`: Terminal window. Snippet mode types install commands once in view (full text stays
in the DOM for SEO and no-JS); log mode streams lines and follows the bottom unless you
scroll up, offering a jump back when new output arrives.
  - `lines: TerminalLine[]`: Lines in order; append to stream a `log`.
  - `bodyClassName?: string`: Size the scrolling body, e.g. "h-64".
  - `copyText?: string | false`: What Copy puts on the clipboard; defaults to the commands. `false` hides it.
  - `log?: boolean` = `false`: Live log: role="log", sticks to the bottom unless you scroll up to read.
  - `prompt?: string` = `"$"`: Symbol before commands.
  - `speed?: number` = `35`: Ms per typed character.
  - `title?: string` = `"Terminal"`: Window title.
  - `typing?: boolean` = `false`: Types the commands and reveals the output once in view (install snippets).

- `type TerminalLine = { id?: string | number; kind?: Kind; text: string; time?: string; }`

### Usage

```tsx
<Terminal typing lines={[{ kind: "command", text: "bun add motion" }, { kind: "success", text: "1 package installed" }]} />
```

### Example: install.tsx

```tsx
import { Terminal } from "@/components/ui/terminal";

// Server-safe props: the lines are plain data. Copy grabs just the commands.
export function Install() {
  return (
    <Terminal
      typing
      lines={[
        { kind: "command", text: "bun add motion lucide-react" },
        { kind: "success", text: "2 packages installed [612ms]" },
      ]}
    />
  );
}
```

### Example: bot-log.tsx

```tsx
"use client";

import { useEffect, useState } from "react";
import { type TerminalLine, Terminal } from "@/components/ui/terminal";

export function BotLog({ url }: { url: string }) {
  const [lines, setLines] = useState<TerminalLine[]>([]);
  useEffect(() => {
    const source = new EventSource(url);
    source.onmessage = (e) => setLines((ls) => [...ls, JSON.parse(e.data)].slice(-500));
    return () => source.close();
  }, [url]);
  return <Terminal title="bot.log" log lines={lines} copyText={false} bodyClassName="h-80" />;
}
```
