---
title: "CodeStream"
description: "A code block with a filename header that streams or reveals code."
category: AiReasoning
status: beta
since: 0.3.9
tags: [ai, code, streaming, highlight]
syncStatus: reviewed
verified: true
---

## Usage

### Streaming
Pass the code received so far as `code` and set `streaming`; the component releases it word by word at a steady pace.
:::TuffDemoWrapper{demo="CodeStreamLiveDemo" code-lang="vue"}
---
code: |
  <script setup lang="ts">
  const code = ref('')
  const busy = ref(true)

  for await (const delta of stream)
    code.value += delta
  busy.value = false
  </script>

  <template>
    <TxCodeStream :code="code" :streaming="busy" lang="ts" filename="churn.ts" />
  </template>
---
:::

### Line-by-Line Reveal
The host advances `revealedLines`; the component owns the transition and the caret.
:::TuffDemoWrapper{demo="CodeStreamStreamingDemo" code-lang="vue"}
---
code: |
  <template>
    <TxCodeStream
      :code="code"
      lang="ts"
      filename="churn.ts"
      lang-label="TypeScript"
      :revealed-lines="revealed"
      @complete="onComplete"
    />
  </template>
---
:::

### Full Listing
Without `revealedLines` and `streaming`, the whole listing shows.
:::TuffDemoWrapper{demo="CodeStreamStaticDemo" code-lang="vue"}
---
code: |
  <template>
    <TxCodeStream
      :code="code"
      lang="ts"
      filename="inventory.ts"
      lang-label="TypeScript"
    />
  </template>
---
:::

### Unified Diff
`diff` renders a unified diff. A removed row and the added row replacing it share a number, so numbers are given per row.
:::TuffDemoWrapper{demo="CodeStreamDiffDemo" code-lang="vue"}
---
code: |
  <script setup lang="ts">
  const CODE = `...the new revision in full, for the copy button...`

  const diff = [
    { number: 3, content: '  const base = await dairy.fetch({ flavor })' },
    { number: 4, kind: 'removed', content: '  await freezer.store(base, { temp: "-14C" })' },
    { number: 4, kind: 'added', content: '  await freezer.store(base, { temp: "-16C" })' },
    { number: 5, kind: 'added', content: '  if (!base.approved) return null' },
  ]
  </script>

  <template>
    <TxCodeStream :code="CODE" :diff="diff" lang="ts" filename="churn.ts" />
  </template>
---
:::

### Best Practices

- Use `streaming` for code arriving from a model and let the component pace it; use `revealedLines` only when the host owns the cadence (a scripted replay, a log).
- In streaming mode the box grows with its lines; set `minHeight` to the final height when the page below must not move, and `reserve` for playback of complete code.
- When the language is uncertain, omit `lang`: plain text is always correct.
- Put long listings in an outer scroll container; the code area scrolls only horizontally and its height follows content.
- Use `TxCodeBlock` to match `TxStreamMarkdown` fences; use this component for a filename header, line numbers, and a line-by-line reveal.

## API Reference

### Props

| Prop | Type | Default | Description |
|------|------|---------|------|
| `code` | `string` | — | The source. Required. |
| `lang` | `string` | `''` | Shiki language id; empty skips highlighting and never loads Shiki. |
| `filename` | `string` | — | Header filename, in the mono face. |
| `langLabel` | `string` | — | Language label beside the filename, e.g. `TypeScript`. |
| `revealedLines` | `number` | — | Lines revealed, clamped to range; omit or pass `-1` for all. |
| `streaming` | `boolean` | — | Streaming mode: the source is live; `false` shows the code at once and allows `replay()`. |
| `reveal` | `'aurora' \| 'hue' \| 'blur' \| 'languid' \| 'none'` | `'aurora'` | Streaming mode: how a word enters. Code keeps its syntax color: `aurora` equals `blur`, `hue` is a fade. |
| `wordMs` | `number` | `24` | Streaming mode: releases one word every `wordMs`. |
| `maxLagMs` | `number` | `600` | Streaming mode: no word shows later than this after it arrives. |
| `drainMs` | `number` | `320` | Streaming mode: once `streaming` turns false, releases the rest within this. |
| `pauseMs` | `number` | `400` | Streaming mode: reports `paused` after this long without a new word. |
| `reserve` | `boolean` | `false` | Streaming mode: holds the full height while complete code plays back; ignored while `streaming`. |
| `paced` | `boolean` | `true` | Streaming mode: `false` shows each word as it arrives, still animated; `TxStreamElement` passes it to pace parts itself. |
| `appear` | `boolean` | `false` | Streaming mode: code present at mount enters too. Read at mount. |
| `caret` | `boolean` | `true` | A still end-of-line marker with `revealedLines`, the Tuff caret in streaming mode; off removes it at once. |
| `lineNumbers` | `boolean` | `true` | Shows line numbers. |
| `theme` | `'light' \| 'dark' \| 'auto'` | `'auto'` | Highlight theme; `'auto'` follows the document root's `data-theme` or `.dark`. |
| `copyable` | `boolean` | `true` | Renders the copy button. |
| `copyLabel` | `string` | `'Copy'` | Copy button text; localize it together with `copiedLabel`. |
| `copiedLabel` | `string` | `'Copied'` | Text shown after a successful copy. |
| `minHeight` | `number \| string` | — | Floor for the code area; defaults to the full listing's height. |
| `diff` | `CodeDiffRow[]` | — | Unified diff rows; renders them with an added/removed tally. The copy button still yields `code`. |

### Events

| Event | Payload | Description |
|------|------|------|
| `copy` | `(code: string)` | Fires after a successful copy. |
| `complete` | — | Fires once when `revealedLines` reaches the last line; not when mounted complete, nor in streaming mode. |
| `state-change` | `(state: StreamState)` | Streaming mode: fires when the state changes. |
| `done` | — | Streaming mode: fires once per play-through. |

### Slots

| Name | Scope | Description |
|------|------|------|
| `header` | — | Replaces the filename and language label. |
| `actions` | — | Custom controls before the copy button. |
| `caret` | `{ state }` | Streaming mode: replaces the Tuff caret; rendered only while live. |

### Exposed Methods

| Name | Type | Description |
|------|------|------|
| `state` | `StreamState` | The streaming-mode state; `idle` in the other modes. |
| `replay` | `() => void` | Streaming mode: plays the code again from the first word. |
| `skip` | `() => void` | Streaming mode: shows everything now, without entrances. |

### Types

#### CodeDiffRow

| Field | Type | Description |
|---|---|---|
| `content` | `string` | The row's text, without a `+` / `-` marker. |
| `kind` | `'context' \| 'added' \| 'removed'` | Defaults to `'context'`. |
| `number` | `number` | Gutter number; a removed row and its replacement usually share one. Omit to leave it blank. |

## Overview

- Setting `streaming` (`true` or `false`) without `revealedLines` or a non-empty `diff` selects streaming mode; its pacing, states, and incremental reveal match [StreamText](./stream-text.en.mdc).
- With `revealedLines`, the caret appears only while revealing (`0 < revealedLines < total`), still, at the end of the last line.
- Removed rows take a hatched gutter marker and added rows a solid one, so the distinction never rests on red and green alone.
- Only Shiki-generated markup reaches `v-html`, with the code text escaped; unhighlighted code is plain interpolation.
- Under reduced motion no line or word entrance plays: `revealedLines` still reveals, streaming mode shows code as it arrives, and the caret rests.

## Technologies

- Highlighting reuses `TxCodeBlock`'s lazy Shiki singleton: plain text renders first and color arrives asynchronously. `TxStreamCode` is an alias of the same component.
- Adapted from [Beautiful UI](https://www.beautifului.dev) (© 2026 Shane Levine, MIT).
- Source: `packages/tuffex/packages/components/src/code-stream/`.

<TuffDocSourceLink />
