npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

react-tree-stream

v1.2.0

Published

Stream React trees recursively, LLM-style progressive rendering.

Downloads

55

Readme

React Tree Stream

npm version

A flexible React component for creating "streaming" or "typewriter" effects on your content. It walks your React tree sequentially, streaming text over time and treating elements as atomic units in the flow.

Features

  • Text Streaming: Renders text content word-by-word or character-by-character.
  • Element Sequencing: Plain React elements count as single units in the stream.
  • Nested Streams: Supports nesting TreeStream components, waiting for each to complete before continuing.
  • Customizable: Control streaming speed, timing, and the underlying HTML element.
  • Observability: Subscribe to run and unit lifecycle callbacks for diagnostics or orchestration.
  • Callbacks: onComplete event fires when the entire stream is finished.
  • Dynamic Content: Automatically restarts the stream if its children change.
  • Styling Hooks: Provides data-streaming and data-complete attributes for easy CSS styling.
  • Type-Safe: Fully typed with TypeScript, including props for the underlying element.

Installation

npm install react-tree-stream
# or
yarn add react-tree-stream

Usage

Basic Example

Wrap your content with TreeStream to start streaming.

import { TreeStream } from 'react-tree-stream';

function App() {
  return (
    <TreeStream>
      This is a simple example of streaming text content. The component will render this sentence
      word by word.
    </TreeStream>
  );
}

Mixed Content

TreeStream can handle a mix of text and React components. Text is tokenized and streamed over time, while plain React elements appear as atomic units when their turn is reached.

import { TreeStream } from 'react-tree-stream';

const MyComponent = () => (
  <div style={{ padding: '1rem', background: '#eee' }}>I am a component!</div>
);

function App() {
  return (
    <TreeStream speed={1} interval={80}>
      Here is some text.
      <MyComponent />
      And here is some more text that will appear after the component.
    </TreeStream>
  );
}

In this example:

  • Here is some text. streams according to streamBy
  • <MyComponent /> appears as one sequenced unit
  • the trailing text resumes after that element

Nested Streams

You can nest TreeStream components. A nested TreeStream is one unit in the parent flow, but it can stream its own contents internally. The parent stream pauses and waits for the nested stream to complete before it continues.

import { TreeStream } from 'react-tree-stream';

function App() {
  return (
    <TreeStream>
      This is the parent stream. It will pause here...
      <TreeStream as="blockquote" speed={10}>
        ...and this nested stream will run to completion. Once it's done...
      </TreeStream>
      ...the parent stream will resume.
    </TreeStream>
  );
}

Character-by-Character Streaming

By default, TreeStream streams text content word-by-word. You can change this behavior to stream text character-by-character.

import { TreeStream } from 'react-tree-stream';

function App() {
  return (
    <TreeStream streamBy="character">
      This text is being streamed one character at a time. You can change the streaming behavior
      to be more granular.
    </TreeStream>
  );
}

Mental Model

TreeStream turns its direct children into a linear execution plan:

  • Plain text becomes streamed text tokens
  • Plain React elements become one atomic sequenced unit
  • Nested TreeStream elements become one sequenced unit that may stream internally

This means you control grouping through normal React structure:

  • Want several things to appear together: wrap them in a single non-TreeStream element
  • Want sibling elements to appear one-by-one: render them as siblings
  • Want an element's own contents to stream: render that subtree as TreeStream

Example:

<TreeStream speed={1} interval={50}>
  <a>Some link</a>
  <a>Another link</a>
  <TreeStream as="strong">Emphasized text</TreeStream>
  And then some trailing text
</TreeStream>

With this setup:

  • each <a> counts as one unit in the parent stream
  • <TreeStream as="strong"> counts as one parent unit, but streams inside the <strong>
  • the trailing text streams after those units are reached

Polymorphic as prop

TreeStream is polymorphic: you can render it as any element or component using as?: React.ElementType.

  • Semantic tags: <TreeStream as="section" role="region">...
  • Custom components: pass your wrapper and forward props to a DOM element so data-*, className, and style reach the node.
  • Fragments: <TreeStream as={React.Fragment}> renders no wrapper. In this mode, DOM-specific props like className and style are disallowed and the data-* attributes are not rendered (no wrapper node).

Example custom wrapper:

const Custom = ({ children, ...rest }: React.PropsWithChildren<React.ComponentPropsWithoutRef<'div'>>) => (
  <div {...rest}>{children}</div>
);

<TreeStream as={Custom} className="panel" data-testid="stream">Text</TreeStream>

When using as={React.Fragment}, omit DOM-only props:

<TreeStream as={React.Fragment}>No wrapper here</TreeStream>

API and Props

The component accepts the following props:

| Prop | Type | Default | Description | | ------------ | ---------------------------------- | ------- | ------------------------------------------------------------------------------------------------------- | | as | React.ElementType | 'div' | The element or component to render as the root; supports intrinsic tags, custom components, or React.Fragment. | | children | React.ReactNode | | The content to be streamed. | | speed | number | 5 | The number of units to advance per tick. Units are words, characters, plain elements, or nested TreeStream boundaries. | | interval | number | 50 | The delay in milliseconds between rendering ticks. | | autoStart | boolean | true | If true, the stream starts automatically on mount. If false, it waits for autoStart to become true. | | onStart | () => void | | Called when a new stream run starts. | | onUnitStart| (event) => void | | Called when a unit begins processing. | | onUnitComplete | (event) => void | | Called when a unit completes processing. | | onComplete | () => void | | A callback function that is invoked when the entire stream has finished rendering. | | streamBy | 'word' \| 'character' | 'word'| Determines the granularity of the streaming. Use 'word' for word-by-word streaming or 'character' for character-by-character streaming. | | ...rest | ComponentPropsWithoutRef<typeof as> | | Any other props are forwarded to the chosen element/component. For React.Fragment, DOM-only props are not allowed. |

onUnitStart and onUnitComplete receive { unitIndex, unit }, where unit.type is one of text_stream, instant_render, or nested_stream.

Styling

The root element rendered by TreeStream includes data attributes that reflect its current state, which you can use for styling.

  • data-tree-stream: Always present on the component's root element.
  • data-streaming="true": Present while the component is actively streaming text or waiting for a nested stream.
  • data-complete="true": Present when the stream has finished.

Example: Blinking Cursor

You can use these attributes to create a blinking cursor effect that appears only during streaming.

/* Your CSS file */
[data-streaming='true']::after {
  content: '▋';
  animation: blink 1s step-end infinite;
}

@keyframes blink {
  50% {
    opacity: 0;
  }
}