After sharing my portfolio project on DEV, a fellow community member commented asking how I built the retro terminal panel. So, I decided to break down the logic and share the details here!
The goal was to show a series of commands and outputs, just like a real terminal, and animate them. I also wanted a blinking cursor and a “reset” effect after all lines are shown.
The State
I used React’s useState to keep track of the lines currently displayed in the terminal:
const [terminalLines, setTerminalLines] = useState([] as string[]);
The Commands
I defined the commands and outputs as an array:
const terminalCommands = [ '> whoami', 'ngawang_tenzin', '> cat skills.txt', 'React.js | Node.js | Python | TypeScript', '> ls projects/', 'barma-sorig-web-app/ | quiz-mobile-app/ | portfolio-website/', '> status', 'AVAILABLE FOR HIRE', '> echo "Let\'s build something amazing!"', "Let's build something amazing!" ];
The Animation Logic
I used useEffect to set up an interval that adds one line at a time to the terminal. Here’s the core logic:
useEffect(() => { let terminalInterval: ReturnType<typeof setInterval> | undefined; let lineIndex = 0; if (isRetroMode) { terminalInterval = setInterval(() => { if (lineIndex < terminalCommands.length && terminalCommands[lineIndex]) { setTerminalLines(prev => { const newLines = prev.slice(); newLines.push(terminalCommands[lineIndex]); return newLines; }); lineIndex++; } else { setTimeout(() => { setTerminalLines([]); lineIndex = 0; }, 3000); } }, 800); } else { setTerminalLines([]); } return () => { if (terminalInterval) clearInterval(terminalInterval); }; }, [isRetroMode]);
- Every 800ms, a new line is added.
- When all lines are shown, it waits 3 seconds, then resets the terminal.
The Styling
I used CSS to get the neon green text, dark background, and blinking cursor. Here’s a snippet:
.terminal-line.command { color: #00ff41; } .terminal-line.output { color: #cccccc; margin-left: 1rem; } .terminal-cursor { color: #00ff41; animation: blink 1s infinite; } @keyframes blink { 0%, 50% { opacity: 1; } 51%, 100% { opacity: 0; } }
Result
The result is a dynamic, animated terminal panel that brings a retro vibe to my portfolio. It’s all handled with React state and effects, making it easy to customize and integrate with the rest of my site.
Top comments (1)
🔥❤️ cool