Terminal
loomui/terminalFreeComponent
A window that types its commands out and prints their output a beat later.
Live preview
live · rendered by the registry
Rendered by loomui on their own page — this is the component running, not a screenshot of it.Install it
npx shadcn@latest add https://loomui.design/r/terminal.jsonSource
1"use client"23import * as React from "react"45import { cn } from "@/lib/utils"67interface LineState {8 /** This line is the one currently running. */9 active: boolean10 /** Milliseconds per character, inherited from the terminal. */11 speed: number12 /** Play everything at once with no typing. */13 instant: boolean14 /** Hand the session on to the next line. */15 done: () => void16}1718const LineContext = React.createContext<LineState>({19 active: false,20 speed: 34,21 instant: true,22 done: () => {},23})2425export interface TerminalProps extends React.ComponentProps<"div"> {26 /** Text in the window bar. A path or a shell name, usually. */27 title?: string28 /** Milliseconds a single character takes to be typed. */29 speed?: number30 /** Hold the session until the window scrolls into view. */31 startOnView?: boolean32 /** Print the whole session at once with no typing. */33 instant?: boolean34}3536/**37 * Lines are rendered as the session reaches them rather than hidden and38 * revealed, so a line that has not run yet is not in the document at all and39 * cannot be read out ahead of itself.40 */41export function Terminal({42 children,43 className,44 title = "bash",45 speed = 34,46 startOnView = true,47 instant = false,48 ...props49}: TerminalProps) {50 const ref = React.useRef<HTMLDivElement>(null)51 const lines = React.Children.toArray(children)52 const [started, setStarted] = React.useState(!startOnView)53 const [step, setStep] = React.useState(0)54 const [reduced, setReduced] = React.useState(false)5556 React.useEffect(() => {57 setReduced(window.matchMedia("(prefers-reduced-motion: reduce)").matches)58 }, [])5960 React.useEffect(() => {61 if (!startOnView) {62 return63 }6465 const node = ref.current66 if (!node || typeof IntersectionObserver === "undefined") {67 setStarted(true)68 return69 }7071 const observer = new IntersectionObserver(72 ([entry]) => {73 if (entry.isIntersecting) {74 setStarted(true)75 observer.disconnect()76 }77 },78 { threshold: 0.3 }79 )8081 observer.observe(node)82 return () => observer.disconnect()83 }, [startOnView])8485 const atOnce = instant || reduced86 const reached = atOnce ? lines.length - 1 : step8788 return (89 <div90 ref={ref}91 data-slot="terminal"92 className={cn(93 "border-border bg-card w-full overflow-hidden rounded-xl border font-mono text-sm",94 className95 )}96 {...props}97 >98// … truncated
What it pulls in
Other registry items
Files it writes
More from loomui
All 91 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Aurora Backdropaurora-backdrop | loomui | Components | Free | no deps | |
| Bento Gridbento-grid | loomui | Components | Free | no deps | |
| Card Stackcard-stack | loomui | Components | Free | no deps | |
| Compare Slidercompare-slider | loomui | Components | Free | no deps | |
| Confetti Buttonconfetti-button | loomui | Components | Free | no deps | |
| Count Upcount-up | loomui | Components | Free | no deps | |
| Credit Cardcredit-card | loomui | Components | Free | no deps | |
| Drawerdrawer | loomui | Components | Free | 1 dep |
