AI Snippet

Copy. Paste. Ship.

Home › Code Snippets › AI › Streaming Text

Snippet

Streaming Text Reveal

ChatGPT-style token-by-token text reveal with a blinking cursor and stop button.

Last updated: October 2026

What this snippet does: Renders text one character at a time, mimicking the streaming output of AI models like ChatGPT and Claude. Includes a blinking cursor and a stop button. Pure HTML, CSS, and vanilla JavaScript — no dependencies, no build step.

🎬 Live Demo

Click Start to see the streaming effect.

💡 The cursor blinks while streaming and disappears when done.

📝

How It Works

Text is appended one character at a time using setInterval. The cursor is a separate span that stays at the end. When streaming finishes, the cursor is removed.

1

HTML

<div class="stream-container">
  <div class="stream-output" id="output"></div>
  <div class="stream-controls">
    <button id="start">▶ Start</button>
    <button id="stop" disabled>⏹ Stop</button>
    <button id="reset">↺ Reset</button>
  </div>
</div>
2

CSS

.stream-output {
  font-family: 'Inter', sans-serif;
  font-size: 1rem;
  line-height: 1.7;
  color: #e2e8f0;
  white-space: pre-wrap;
  word-wrap: break-word;
  min-height: 3rem;
}

.stream-cursor {
  display: inline-block;
  width: 0.5ch;
  height: 1.1em;
  background: #3b82f6;
  margin-left: 2px;
  vertical-align: text-bottom;
  animation: blink 1s step-end infinite;
}

@keyframes blink {
  0%, 100% { opacity: 1; }
  50% { opacity: 0; }
}
3

JavaScript

const TEXT = "Your streaming text here...";

const output = document.getElementById('output');
const startBtn = document.getElementById('start');
const stopBtn = document.getElementById('stop');
const resetBtn = document.getElementById('reset');

let intervalId = null;
let cursor = null;

function createCursor() {
  cursor = document.createElement('span');
  cursor.className = 'stream-cursor';
  output.appendChild(cursor);
}

function removeCursor() {
  if (cursor && cursor.parentNode) {
    cursor.parentNode.removeChild(cursor);
  }
  cursor = null;
}

function startStream() {
  if (intervalId) return;
  output.textContent = '';
  createCursor();

  let i = 0;
  intervalId = setInterval(() => {
    if (i >= TEXT.length) {
      stopStream();
      return;
    }
    cursor.insertAdjacentText('beforebegin', TEXT[i]);
    i++;
  }, 25);

  startBtn.disabled = true;
  stopBtn.disabled = false;
}

function stopStream() {
  if (intervalId) {
    clearInterval(intervalId);
    intervalId = null;
  }
  removeCursor();
  startBtn.disabled = false;
  stopBtn.disabled = true;
}

function resetStream() {
  stopStream();
  output.textContent = '';
}

startBtn.addEventListener('click', startStream);
stopBtn.addEventListener('click', stopStream);
resetBtn.addEventListener('click', resetStream);
4

Using a Real AI API

Replace the simulated interval with a real streaming fetch:

async function streamFromAPI(prompt) {
  output.textContent = '';
  createCursor();

  const res = await fetch('/api/chat', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ prompt })
  });

  const reader = res.body.getReader();
  const decoder = new TextDecoder();

  while (true) {
    const { done, value } = await reader.read();
    if (done) break;
    const chunk = decoder.decode(value, { stream: true });
    cursor.insertAdjacentText('beforebegin', chunk);
  }

  removeCursor();
}

Pro tip: For OpenAI/Anthropic APIs, set stream: true in the request body and read chunks from the response body.

🎨 Customization

Property Effect Default
intervalSpeed of reveal25ms
background (cursor)Cursor color#3b82f6
font-sizeText size1rem

🎯 Use Cases

⚠️ Common Mistakes

❓ Frequently Asked Questions

How does streaming text work in AI apps?

The model returns tokens over a stream (SSE or WebSocket). The UI appends each token to the DOM as it arrives, giving the effect of text being typed in real time.

Do I need a library for streaming text?

No. This snippet uses vanilla JavaScript with setInterval or requestAnimationFrame. Works in any modern browser without dependencies.

How do I stop streaming mid-way?

Store the interval or animation frame ID and clear it on stop. This snippet includes a Stop button that does exactly that.

Can I use this with a real AI API?

Yes. Replace the simulated interval with your actual API call using fetch() with a ReadableStream reader or EventSource for SSE.

Does this work on mobile?

Yes. The layout is responsive and uses no fixed widths. The cursor animation uses CSS only.

🎯 What's Next?

← AI Hub