StreamMarkdown class

A widget that renders Markdown content from a stream in real-time.

StreamMarkdown is designed specifically for streaming scenarios where markdown content arrives incrementally, such as AI chat responses, live documentation updates, or collaborative editing. It efficiently accumulates and renders text chunks as they arrive from a stream.

Basic Usage

StreamController<String> controller = StreamController<String>();

// Display the streaming widget
StreamMarkdown(
  stream: controller.stream,
  styleSheet: MarkdownStyleSheet.light(),
)

// Later, send chunks to the stream
controller.add('# Hello\n\n');
await Future.delayed(Duration(milliseconds: 100));
controller.add('This is **streaming** ');
await Future.delayed(Duration(milliseconds: 100));
controller.add('markdown!');

Use Cases

AI Chat Applications: Perfect for displaying streaming LLM responses

StreamMarkdown(
  stream: openAI.streamCompletion(prompt),
  styleSheet: MarkdownStyleSheet.github(),
  useEnhancedComponents: true,
)

Live Collaboration: Show real-time updates from multiple users

StreamMarkdown(
  stream: firestore
    .collection('documents')
    .doc(docId)
    .snapshots()
    .map((doc) => doc.data()['content'] as String),
  styleSheet: MarkdownStyleSheet.light(),
)

Progressive Loading: Display content as it loads from network

StreamMarkdown(
  stream: fetchLargeDocument(),
  loadingWidget: Center(child: CircularProgressIndicator()),
)

How It Works

  1. The widget listens to the provided stream
  2. Each chunk received is appended to an internal buffer
  3. The accumulated text is parsed and rendered on each update
  4. The UI updates smoothly as new content arrives

Performance Considerations

  • The widget re-parses and re-renders the entire accumulated content on each chunk
  • For very large documents with frequent updates, consider batching chunks
  • The parsing is fast (AST-based), but very large documents may cause frame drops
  • Consider using SmoothMarkdown for static content instead

Error Handling

Currently, stream errors are silently ignored. The errorBuilder parameter is available but not yet fully implemented. To handle errors:

final stream = sourceStream.handleError((error) {
  print('Stream error: $error');
  // You can transform errors or rethrow
});

StreamMarkdown(stream: stream)

See also:

Inheritance

Constructors

StreamMarkdown({required Stream<String> stream, Key? key, MarkdownStyleSheet? styleSheet, MarkdownConfig? config, void onTapLink(String url)?, Widget imageBuilder(String url, String? alt, String? title)?, Widget codeBuilder(String code, String? language)?, bool useEnhancedComponents = false, Widget? loadingWidget, Widget errorBuilder(Object error)?, ParserPluginRegistry? plugins, BuilderRegistry? builderRegistry})
Creates a widget that renders streaming Markdown content.
const

Properties

builderRegistry BuilderRegistry?
Custom widget builder registry for rendering plugin nodes.
final
codeBuilder Widget Function(String code, String? language)?
Custom widget builder for rendering code blocks.
final
config MarkdownConfig?
Configuration options for Markdown parsing behavior.
final
errorBuilder Widget Function(Object error)?
Custom widget builder for displaying stream errors.
final
hashCode int
The hash code for this object.
no setterinherited
imageBuilder Widget Function(String url, String? alt, String? title)?
Custom widget builder for rendering images.
final
key Key?
Controls how one widget replaces another widget in the tree.
finalinherited
loadingWidget Widget?
Widget to display while waiting for the first chunk from the stream.
final
Callback function invoked when a user taps on a link.
final
plugins ParserPluginRegistry?
Parser plugins for extending markdown syntax.
final
runtimeType Type
A representation of the runtime type of the object.
no setterinherited
stream Stream<String>
The stream of Markdown text chunks to render.
final
styleSheet MarkdownStyleSheet?
The style sheet used to control the visual appearance of rendered markdown.
final
useEnhancedComponents bool
Whether to use enhanced UI components with additional visual effects.
final

Methods

createElement() StatefulElement
Creates a StatefulElement to manage this widget's location in the tree.
inherited
createState() State<StreamMarkdown>
Creates the mutable state for this widget at a given location in the tree.
override
debugDescribeChildren() List<DiagnosticsNode>
Returns a list of DiagnosticsNode objects describing this node's children.
inherited
debugFillProperties(DiagnosticPropertiesBuilder properties) → void
Add additional properties associated with the node.
inherited
noSuchMethod(Invocation invocation) → dynamic
Invoked when a nonexistent method or property is accessed.
inherited
toDiagnosticsNode({String? name, DiagnosticsTreeStyle? style}) DiagnosticsNode
Returns a debug representation of the object that is used by debugging tools and by DiagnosticsNode.toStringDeep.
inherited
toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) String
A string representation of this object.
inherited
toStringDeep({String prefixLineOne = '', String? prefixOtherLines, DiagnosticLevel minLevel = DiagnosticLevel.debug, int wrapWidth = 65}) String
Returns a string representation of this node and its descendants.
inherited
toStringShallow({String joiner = ', ', DiagnosticLevel minLevel = DiagnosticLevel.debug}) String
Returns a one-line detailed description of the object.
inherited
toStringShort() String
A short, textual description of this widget.
inherited

Operators

operator ==(Object other) bool
The equality operator.
inherited