StreamingTextMarkdown class

A widget that displays streaming text with Markdown support.

This widget combines the power of markdown rendering with smooth typing animations. It supports:

  • Markdown formatting (headers, bold, italic, lists)
  • Character-by-character or word-by-word typing
  • Customizable typing speed and animations
  • RTL language support
  • Auto-scrolling
  • Theme support through StreamingTextTheme

Provide either text (static markdown string, the default) or stream (a Stream<String> of chunks from an LLM API). When stream is non-null, text is ignored entirely — the stream starts from an empty buffer and content is appended as it emits.

Use typingSpeed to control how fast each character or word appears, and wordByWord to choose between character-by-character or word-by-word animation. For unbounded streams, prefer trailingFadeEnabled over fadeInEnabled — per-character fades are auto-disabled when stream is set to avoid spawning one AnimationController per glyph.

Inheritance

Constructors

StreamingTextMarkdown({Key? key, String text = '', Stream<String>? stream, String initialText = '', TextStyle? styleSheet, StreamingTextTheme? theme, EdgeInsets? padding, bool autoScroll = true, bool fadeInEnabled = false, Duration fadeInDuration = const Duration(milliseconds: 300), Curve fadeInCurve = Curves.easeOut, bool wordByWord = false, int chunkSize = 1, Duration typingSpeed = const Duration(milliseconds: 50), TextDirection? textDirection, TextAlign? textAlign, bool markdownEnabled = false, bool latexEnabled = false, TextStyle? latexStyle, double latexScale = 1.0, bool? latexFadeInEnabled, StreamingTextController? controller, VoidCallback? onComplete, bool animationsEnabled = true, bool trailingFadeEnabled = false, bool isLoading = false, int shimmerLineCount = 3, Widget imageBuilder(BuildContext context, String imageUrl)?, void onLinkTap(String url, String title)?, Widget codeBuilder(BuildContext context, String name, String code, bool closed)?, Widget latexBuilder(BuildContext context, String tex, TextStyle textStyle, bool inline)?, Widget sourceTagBuilder(BuildContext context, String content, TextStyle textStyle)?, Widget highlightBuilder(BuildContext context, String content, TextStyle textStyle)?, Widget linkBuilder(BuildContext context, InlineSpan text, String url, TextStyle style)?, List<MarkdownComponent>? components, List<MarkdownComponent>? inlineComponents, MarkdownRenderOptions? markdownOptions, bool selectable = false, bool? showCursor, Color? cursorColor, String? semanticsLabel, Widget errorBuilder(BuildContext context, Object error)?, bool? completeAnimationOnTap, RevealMode? revealMode = RevealMode.smoothFade, StreamPacing? pacing})
Creates a streaming markdown text widget.
const
StreamingTextMarkdown.chatGPT({Key? key, String text = '', Stream<String>? stream, String initialText = '', TextStyle? styleSheet, StreamingTextTheme? theme, EdgeInsets? padding, bool autoScroll = true, TextDirection? textDirection, TextAlign? textAlign, bool markdownEnabled = true, bool latexEnabled = false, TextStyle? latexStyle, double latexScale = 1.0, bool? latexFadeInEnabled, StreamingTextController? controller, VoidCallback? onComplete, bool animationsEnabled = true, bool trailingFadeEnabled = false, bool isLoading = false, int shimmerLineCount = 3, Widget imageBuilder(BuildContext context, String imageUrl)?, void onLinkTap(String url, String title)?, Widget codeBuilder(BuildContext context, String name, String code, bool closed)?, Widget latexBuilder(BuildContext context, String tex, TextStyle textStyle, bool inline)?, Widget sourceTagBuilder(BuildContext context, String content, TextStyle textStyle)?, Widget highlightBuilder(BuildContext context, String content, TextStyle textStyle)?, Widget linkBuilder(BuildContext context, InlineSpan text, String url, TextStyle style)?, List<MarkdownComponent>? components, List<MarkdownComponent>? inlineComponents, MarkdownRenderOptions? markdownOptions, bool selectable = false, bool? showCursor, Color? cursorColor, String? semanticsLabel, Widget errorBuilder(BuildContext context, Object error)?, bool? completeAnimationOnTap, RevealMode? revealMode = RevealMode.smoothFade, StreamPacing? pacing, Duration? fadeInDuration, Curve? fadeInCurve, Duration? typingSpeed})
Creates a StreamingTextMarkdown with ChatGPT-style animation Perfect for fast, character-by-character streaming like ChatGPT
const
StreamingTextMarkdown.claude({Key? key, String text = '', Stream<String>? stream, String initialText = '', TextStyle? styleSheet, StreamingTextTheme? theme, EdgeInsets? padding, bool autoScroll = true, TextDirection? textDirection, TextAlign? textAlign, bool markdownEnabled = true, bool latexEnabled = false, TextStyle? latexStyle, double latexScale = 1.0, bool? latexFadeInEnabled, StreamingTextController? controller, VoidCallback? onComplete, bool animationsEnabled = true, bool trailingFadeEnabled = false, bool isLoading = false, int shimmerLineCount = 3, Widget imageBuilder(BuildContext context, String imageUrl)?, void onLinkTap(String url, String title)?, Widget codeBuilder(BuildContext context, String name, String code, bool closed)?, Widget latexBuilder(BuildContext context, String tex, TextStyle textStyle, bool inline)?, Widget sourceTagBuilder(BuildContext context, String content, TextStyle textStyle)?, Widget highlightBuilder(BuildContext context, String content, TextStyle textStyle)?, Widget linkBuilder(BuildContext context, InlineSpan text, String url, TextStyle style)?, List<MarkdownComponent>? components, List<MarkdownComponent>? inlineComponents, MarkdownRenderOptions? markdownOptions, bool selectable = false, bool? showCursor, Color? cursorColor, String? semanticsLabel, Widget errorBuilder(BuildContext context, Object error)?, bool? completeAnimationOnTap, RevealMode? revealMode = RevealMode.smoothFade, StreamPacing? pacing, Duration? fadeInDuration, Curve? fadeInCurve, Duration? typingSpeed})
Creates a StreamingTextMarkdown with Claude-style animation Perfect for smooth, word-by-word streaming like Claude
const
StreamingTextMarkdown.fromPreset({Key? key, String text = '', Stream<String>? stream, required StreamingTextConfig preset, String initialText = '', TextStyle? styleSheet, StreamingTextTheme? theme, EdgeInsets? padding, bool autoScroll = true, TextDirection? textDirection, TextAlign? textAlign, bool markdownEnabled = false, bool latexEnabled = false, TextStyle? latexStyle, double latexScale = 1.0, bool? latexFadeInEnabled, StreamingTextController? controller, VoidCallback? onComplete, bool animationsEnabled = true, bool trailingFadeEnabled = false, bool isLoading = false, int shimmerLineCount = 3, Widget imageBuilder(BuildContext context, String imageUrl)?, void onLinkTap(String url, String title)?, Widget codeBuilder(BuildContext context, String name, String code, bool closed)?, Widget latexBuilder(BuildContext context, String tex, TextStyle textStyle, bool inline)?, Widget sourceTagBuilder(BuildContext context, String content, TextStyle textStyle)?, Widget highlightBuilder(BuildContext context, String content, TextStyle textStyle)?, Widget linkBuilder(BuildContext context, InlineSpan text, String url, TextStyle style)?, List<MarkdownComponent>? components, List<MarkdownComponent>? inlineComponents, MarkdownRenderOptions? markdownOptions, bool selectable = false, bool? showCursor, Color? cursorColor, String? semanticsLabel, Widget errorBuilder(BuildContext context, Object error)?, bool? completeAnimationOnTap, RevealMode? revealMode, StreamPacing? pacing})
Creates a StreamingTextMarkdown from a preset configuration
StreamingTextMarkdown.instant({Key? key, String text = '', Stream<String>? stream, String initialText = '', TextStyle? styleSheet, StreamingTextTheme? theme, EdgeInsets? padding, bool autoScroll = true, TextDirection? textDirection, TextAlign? textAlign, bool markdownEnabled = false, bool latexEnabled = false, TextStyle? latexStyle, double latexScale = 1.0, bool? latexFadeInEnabled, StreamingTextController? controller, VoidCallback? onComplete, bool animationsEnabled = false, bool trailingFadeEnabled = false, bool isLoading = false, int shimmerLineCount = 3, Widget imageBuilder(BuildContext context, String imageUrl)?, void onLinkTap(String url, String title)?, Widget codeBuilder(BuildContext context, String name, String code, bool closed)?, Widget latexBuilder(BuildContext context, String tex, TextStyle textStyle, bool inline)?, Widget sourceTagBuilder(BuildContext context, String content, TextStyle textStyle)?, Widget highlightBuilder(BuildContext context, String content, TextStyle textStyle)?, Widget linkBuilder(BuildContext context, InlineSpan text, String url, TextStyle style)?, List<MarkdownComponent>? components, List<MarkdownComponent>? inlineComponents, MarkdownRenderOptions? markdownOptions, bool selectable = false, bool? showCursor, Color? cursorColor, String? semanticsLabel, Widget errorBuilder(BuildContext context, Object error)?, bool? completeAnimationOnTap, RevealMode? revealMode = RevealMode.instant, StreamPacing? pacing, Duration? fadeInDuration, Curve? fadeInCurve, Duration? typingSpeed})
Creates a StreamingTextMarkdown with instant display For when speed is priority over animation
const
StreamingTextMarkdown.typewriter({Key? key, String text = '', Stream<String>? stream, String initialText = '', TextStyle? styleSheet, StreamingTextTheme? theme, EdgeInsets? padding, bool autoScroll = true, TextDirection? textDirection, TextAlign? textAlign, bool markdownEnabled = false, bool latexEnabled = false, TextStyle? latexStyle, double latexScale = 1.0, bool? latexFadeInEnabled, StreamingTextController? controller, VoidCallback? onComplete, bool animationsEnabled = true, bool trailingFadeEnabled = false, bool isLoading = false, int shimmerLineCount = 3, Widget imageBuilder(BuildContext context, String imageUrl)?, void onLinkTap(String url, String title)?, Widget codeBuilder(BuildContext context, String name, String code, bool closed)?, Widget latexBuilder(BuildContext context, String tex, TextStyle textStyle, bool inline)?, Widget sourceTagBuilder(BuildContext context, String content, TextStyle textStyle)?, Widget highlightBuilder(BuildContext context, String content, TextStyle textStyle)?, Widget linkBuilder(BuildContext context, InlineSpan text, String url, TextStyle style)?, List<MarkdownComponent>? components, List<MarkdownComponent>? inlineComponents, MarkdownRenderOptions? markdownOptions, bool selectable = false, bool? showCursor, Color? cursorColor, String? semanticsLabel, Widget errorBuilder(BuildContext context, Object error)?, bool? completeAnimationOnTap, RevealMode? revealMode = RevealMode.typewriter, StreamPacing? pacing, Duration? fadeInDuration, Curve? fadeInCurve, Duration? typingSpeed})
Creates a StreamingTextMarkdown with typewriter animation Classic typewriter effect without fade-in
const

Properties

animationsEnabled → bool
Whether animations are enabled. When false, text appears instantly.
final
autoScroll → bool
Whether to scroll automatically as new text arrives
final
chunkSize → int
The number of grapheme clusters revealed per animation tick when wordByWord is false. Ignored in word-by-word mode, where one unit is a whole word instead. A very large value (see StreamingTextMarkdown.instant) reveals effectively everything on the first tick.
final
codeBuilder → Widget Function(BuildContext context, String name, String code, bool closed)?
Custom builder for code blocks in markdown content.
final
completeAnimationOnTap → bool?
Whether tapping the widget jumps the animation to completion.
final
components → List<MarkdownComponent>?
Custom block-level markdown components forwarded to gpt_markdown's GptMarkdown.components. Use this to override how headers, lists, bold, italic, tables, etc. are rendered. When null, the default gpt_markdown component list is used.
final
controller → StreamingTextController?
Controller for programmatic animation control
final
cursorColor → Color?
Color of the blinking cursor shown while showCursor resolves to true. Defaults to the theme's text-primary token.
final
errorBuilder → Widget Function(BuildContext context, Object error)?
Builder invoked when stream emits an error. Receives the error object; the text revealed so far stays on screen either way.
final
fadeInCurve → Curve
The curve to use for the fade-in animation
final
fadeInDuration → Duration
Duration of the fade-in animation
final
fadeInEnabled → bool
Whether each character (or word, in word-by-word mode) fades in as it is revealed. Disabled automatically for Arabic/RTL content. For stream-based usage in StreamingText, use trailingFadeEnabled instead.
final
hashCode → int
The hash code for this object.
no setterinherited
highlightBuilder → Widget Function(BuildContext context, String content, TextStyle textStyle)?
Custom builder for highlighted text in markdown content.
final
imageBuilder → Widget Function(BuildContext context, String imageUrl)?
Custom builder for images in markdown content.
final
initialText → String
Initial text to display before the animation starts.
final
inlineComponents → List<MarkdownComponent>?
Custom inline markdown components forwarded to gpt_markdown's GptMarkdown.inlineComponents. When null, the default inline component list is used.
final
isLoading → bool
Whether to show a shimmer skeleton placeholder instead of the text widget.
final
key → Key?
Controls how one widget replaces another widget in the tree.
finalinherited
latexBuilder → Widget Function(BuildContext context, String tex, TextStyle textStyle, bool inline)?
Custom builder for LaTeX expressions in markdown content.
final
latexEnabled → bool
Whether to enable LaTeX rendering
final
latexFadeInEnabled → bool?
Whether to enable fade-in animations for LaTeX content.
final
latexScale → double
Scale factor for LaTeX equations
final
latexStyle → TextStyle?
Custom style for LaTeX expressions
final
linkBuilder → Widget Function(BuildContext context, InlineSpan text, String url, TextStyle style)?
Custom builder for links in markdown content.
final
markdownEnabled → bool
Whether to enable markdown rendering.
final
markdownOptions → MarkdownRenderOptions?
Bundles gpt_markdown 1.3 pass-throughs that don't have a dedicated top-level parameter of their own (style sheet, block/inline builders, autolink config, ...). Forwarded as-is to the inner StreamingText. See MarkdownRenderOptions.
final
onComplete → VoidCallback?
Callback when animation completes
final
onLinkTap → void Function(String url, String title)?
Callback when a link is tapped in markdown content.
final
pacing → StreamPacing?
How a Stream<String> (or static text) source is paced (DESIGN.md 4.3). When null, stream input defaults to StreamPacing.catchUp and static text input defaults to StreamPacing.fixed using typingSpeed.
final
padding → EdgeInsets?
Padding around the text
final
revealMode → RevealMode?
How revealed text arrives on screen (DESIGN.md section 4). Defaults to RevealMode.smoothFade on this constructor, .chatGPT and .claude. .typewriter and .instant default to their own matching mode.
final
runtimeType → Type
A representation of the runtime type of the object.
no setterinherited
selectable → bool
Whether the rendered text can be selected by the user (wraps the output in a SelectionArea). Defaults to false.
final
semanticsLabel → String?
Semantic label used for accessibility. When set, this label (rather than the revealed text itself) is what's announced/exposed to assistive technology.
final
shimmerLineCount → int
Number of shimmer skeleton lines shown while isLoading is true. Defaults to 3.
final
showCursor → bool?
Whether to show a blinking cursor at the end of the text while animating. When null (the default), resolves to stream != null — a cursor makes sense for a live stream but not for static text.
final
sourceTagBuilder → Widget Function(BuildContext context, String content, TextStyle textStyle)?
Custom builder for source tags in markdown content.
final
stream → Stream<String>?
Optional stream of text chunks from an LLM API (OpenAI, Anthropic, Ollama, etc.). Each emitted string is appended to the rendered text and animated using the active typing settings. When this is non-null the inner streaming engine takes over, text is ignored, and per-character fadeInEnabled is suppressed automatically; use trailingFadeEnabled for a smooth reveal.
final
styleSheet → TextStyle?
Markdown style configuration: a plain TextStyle applied to the markdown renderer as its base text style. Distinct from MarkdownRenderOptions.styleSheet (in markdownOptions), which is a gpt_markdown GptMarkdownStyleSheet for per-component styling (headings, tables, block quotes, etc.).
final
text → String
The text to display. Ignored when stream is also provided — the stream starts from an empty buffer, not from text.
final
textAlign → TextAlign?
The text alignment
final
textDirection → TextDirection?
The text direction
final
theme → StreamingTextTheme?
Custom theme for the widget
final
trailingFadeEnabled → bool
Whether to show a trailing gradient fade at the bottom edge while text is streaming. The fade animates away when streaming completes (using fadeInDuration / fadeInCurve for the dismiss animation). Recommended for stream-based usage and works with markdown + RTL content. Defaults to false.
final
typingSpeed → Duration
The speed at which each character or word appears
final
wordByWord → bool
Whether to stream text word by word instead of character by character
final

Methods

createElement() → StatefulElement
Creates a StatefulElement to manage this widget's location in the tree.
inherited
createState() → State<StreamingTextMarkdown>
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