OWolf

BlogToolsProjectsAboutContact
© 2025 owolf.com
HomeAboutNotesContactPrivacy

2025-06-25 Web Development

Building a Smooth Typing CLI Response Component in React

By O. Wolfson

When creating user interfaces, even small touches can dramatically affect how users perceive the responsiveness and friendliness of your app. One subtle but powerful UX enhancement is typed-out responses, instead of showing content instantly.

In this article, we’ll walk through building a simple but effective Command Line Interface (CLI)-style React component that responds to hardcoded commands with a smooth, context-aware typing animation — perfect for portfolios, chatbot experiments, or terminal-style playgrounds.

>

✨ What We’re Building

A React component that:

  • Accepts user input like a terminal prompt
  • Responds to predefined commands (e.g. help, about, clear, short, medium, long)
  • Automatically adjusts its typing speed and granularity (character, word, or sentence) based on message length
  • Displays all past interactions in a scrollable console-style interface

⚙️ Technologies Used

  • React (with hooks)
  • Tailwind CSS (for layout and theming)
  • No external libraries — fully client-side

🧱 Component Breakdown

1. history State

Stores all terminal lines — each one tagged as user input or system output.

ts
type Line = { type: "input" | "output"; content: string };

This forms the scrollable history log you see in the console.

2. input State

Tracks the current value of the user's text input.

3. pendingOutput and isTyping

Control the output animation phase. When a command is submitted, the corresponding response is added to pendingOutput, and the typing logic begins.


🧠 Smart Typing Modes

To avoid long delays for lengthy messages, the component adjusts how it renders responses based on their length:

Message LengthModeBehaviorSpeed
≤ 200 charscharRenders letter by letter20ms/tick
201–500 charswordRenders word by word50ms/tick
> 500 charssentenceRenders sentence by sentence150ms/tick

This keeps the animation effect pleasant without making long messages feel sluggish.


🎬 Typing Logic (Simplified)

ts
useEffect(() => {
  const mode = getTypingMode(pendingOutput); // "char" | "word" | "sentence"
  const parts = splitByMode(pendingOutput, mode); // split string by units
  let index = 0;

  const interval = setInterval(() => {
    setHistory((prev) => {
      const newContent = parts
        .slice(0, index + 1)
        .join(mode === "char" ? "" : " ");
      const updated = [...prev];
      const last = updated[updated.length - 1];

      if (last?.type === "output") {
        updated[updated.length - 1].content = newContent;
      } else {
        updated.push({ type: "output", content: newContent });
      }

      return updated;
    });

    index++;
    if (index >= parts.length) {
      clearInterval(interval);
      setIsTyping(false);
      setPendingOutput("");
    }
  }, getDelayForMode(mode));
}, [isTyping, pendingOutput]);

📖 Supported Commands

ts
const RESPONSES = {
  help: `Available commands:\n- help\n- about\n- contact\n- clear\n- short\n- medium\n- long`,

  about: `This is a simple demonstration of a command console component that uses a typewriter-style animation to render responses.

Typing animations can greatly enhance perceived interactivity and responsiveness in user interfaces, even in basic terminal-like environments.

This demo is written in React using functional components and hooks. It can easily be extended with additional commands, real-time data fetching, or even connected to a backend.

Try typing 'help' to see available commands, or 'clear' to reset the console.`,

  contact: `Email: contact@example.com\nTwitter: @example`,

  short: `This is short.`,

  medium: `This is a medium-length message designed to demonstrate how each word appears one after the other with smooth timing, simulating a thoughtful typing pace.`,

  long: `This is a long-form demonstration designed to show how sentence-based rendering improves readability and performance.

When a message exceeds a certain length, typing each individual character becomes tedious and unnecessary. Instead, we chunk the message into sentences and display them with a natural delay.

This balances responsiveness with user experience, especially in UIs where content is meant to be skimmed or understood quickly, like help messages or documentation previews.`,
};

🧼 Special Command: clear

Typing clear wipes the console history instantly:

ts
if (command === "clear") {
  setHistory([]);
  return;
}

🖥 Full User Flow

  1. User types a command and hits Enter
  2. If a response is found, it’s typed out with appropriate pacing
  3. Otherwise, the user sees a “Command not found” message
  4. History is preserved until clear is used

💡 Possible Extensions

You could easily expand this component with:

  • ↑/↓ command history navigation
  • Custom prompt indicators or cursor styles
  • Sound effects per tick or typing chunk
  • Integration with external APIs for dynamic data
  • Markdown formatting (e.g., bold, headers, links)
  • Theme toggles for dark/light terminal styles

🧪 Conclusion

This enhanced command console is a lightweight yet powerful tool for adding retro-flavored interactivity to any web app. By dynamically adjusting how responses are rendered, you get a UX that feels responsive for short replies and efficient for long-form content.

Perfect use cases:

  • Developer portfolios
  • AI/chatbot experiments
  • Internal tools
  • Retro-inspired UI demos