gpt_markdown logo

gpt_markdown

The Flutter renderer for AI output.

Production-grade Markdown and LaTeX rendering for streaming Flutter AI interfaces.
Render rich assistant replies, math, code, tables, citations, images, and custom inline UI in one widget.

CI Pub Version Pub Likes Pub Points BSD-3-Clause license

๐ŸŒ Website ยท ๐Ÿ“– Documentation ยท ๐ŸŽฎ Live Playground ยท ๐Ÿ“ฆ pub.dev


โœจ Why gpt_markdown?

  • Built for AI output โ€” Markdown, LaTeX, code blocks, tables, citations, images, task lists, and mixed rich content in one response.
  • Streaming that stays fast โ€” only the live tail rebuilds while settled content is cached, keeping the rendering cost stable as replies grow.
  • Production-level control โ€” style sheets, Flutter theme extensions, component builders, callbacks, and custom components.
  • Extensible inline UI โ€” add @mentions, #channels, :emoji:, issue references, and product-specific syntax without forking the renderer.
  • Designed for real-world edge cases โ€” RTL, text scaling, selection, malformed Markdown, autolinks, nested content, reduced motion, Flutter web, and WASM.

๐Ÿงฉ Everything AI output needs

Rendering Production experience Extensibility
๐Ÿ“ Rich Markdown โšก Adaptive streaming ๐ŸŽจ Component style sheet
โˆ‘ Inline and block LaTeX ๐Ÿš€ Stable per-token cost ๐Ÿงฑ Structural builders
๐Ÿ’ป Inline and fenced code โ™ฟ Selection and text scaling ๐Ÿท๏ธ Mentions, channels, and emoji
๐Ÿ“Š Tables and aligned columns ๐ŸŒ RTL, web, and WASM ๐Ÿงฉ Custom components and scopes
๐Ÿ”— Links, autolinks, and images ๐ŸŒ“ Theme-aware rendering ๐Ÿ‘† Interaction callbacks
โ˜‘๏ธ Lists, tasks, and citations ๐Ÿ›ก๏ธ Graceful malformed input ๐Ÿ“ฑ Custom URL schemes

A complete assistant response, rendered by one widget

Markdown and LaTeX rendered by gpt_markdown

๐Ÿ› ๏ธ Quick start

flutter pub add gpt_markdown
import 'package:gpt_markdown/gpt_markdown.dart';

GptMarkdown(
  reply,
  onLinkTap: (url, title) => openUrl(url),
)

The widget sizes itself to its content. Place it inside your preferred scrollable chat or document surface.

โšก Streaming AI responses

Rebuild GptMarkdown with the complete text received so far. The settled prefix is cached and only the part that can still change is rebuilt.

GptMarkdown(
  streamedReply,
  animation: GptMarkdownAnimation.fade,
  isStreaming: stillGenerating,
  charactersPerSecond: 300,
)

The reveal adapts when tokens arrive quickly, fast-forwards when generation finishes, avoids unsafe splits inside code fences and block math, and automatically respects reduced-motion settings.

๐Ÿ“ Markdown, LaTeX, and rich AI output

GptMarkdown(
  r'''
## Revenue forecast

The projected growth is **18%**, based on:

\[
R_{next} = R_{current} \times (1 + 0.18)
\]

| Quarter | Revenue |
|:-------:|--------:|
| Q1      | $120K   |
| Q2      | $142K   |

```dart
final growth = currentRevenue * 1.18;
```

- [x] Validate the assumptions
- [ ] Review the final forecast

Sources: [1] [2]
  ''',
  onLinkTap: (url, title) => openUrl(url),
  onSourceTagTap: (source) => openSource(source),
)

Supported output includes:

  • Headings, bold, italic, strikethrough, underline, and inline code
  • Ordered, unordered, nested, task, and radio lists
  • Links, bare URLs, email autolinks, images, and citations
  • Tables with column alignment and horizontal overflow
  • Inline and block LaTeX using \( ... \) and \[ ... \]
  • Optional dollar-sign LaTeX through useDollarSignsForLatex: true
  • Fenced code blocks with language labels, copy controls, and open-fence streaming support

Wrap the renderer with SelectionArea when selectable output is needed:

SelectionArea(
  child: GptMarkdown(reply),
)

๐ŸŽจ Make it match your product

Use style objects for appearance and builders when you need to replace structure.

GptMarkdown(
  reply,
  styleSheet: const GptMarkdownStyleSheet(
    blockQuote: BlockQuoteStyle(
      barWidth: 4,
      barColor: Colors.indigo,
    ),
    inlineCode: InlineCodeStyle(
      fontFamily: 'GeistMono',
      borderRadius: Radius.circular(6),
    ),
    codeBlock: CodeBlockStyle(
      borderRadius: Radius.circular(12),
      showCopyButton: true,
    ),
    table: TableStyle(
      cellPadding: EdgeInsets.all(10),
    ),
  ),
  onCodeCopy: (code) => trackCopy(code),
  onImageTap: (url) => openImage(url),
)

Set the same styles app-wide with GptMarkdownThemeData, or use builders such as codeBuilder, tableBuilder, headingBuilder, blockQuoteBuilder, and imageBuilder for full structural control.

๐Ÿท๏ธ App-specific inline UI

Render mentions, channels, emoji, issue references, and other product syntax alongside Markdown:

GptMarkdown(
  reply,
  inlinePatterns: [
    InlinePattern.prefixed(
      prefix: '#',
      knownNames: channelNames,
      builder: (context, match, style) => WidgetSpan(
        alignment: PlaceholderAlignment.baseline,
        baseline: TextBaseline.alphabetic,
        child: ChannelChip(
          name: match.group(0)!.substring(1),
        ),
      ),
    ),
  ],
)

Known names are matched longest-first, and patterns do not claim link labels by default. This prevents ambiguous tokens such as #2959 from becoming channels and avoids nested inline widgets that do not paint correctly on iOS.

For deeper integrations, use MarkdownComponent, InlineMd, and BlockMd. Components can declare support for content, linkLabel, tableCell, and heading scopes.

Bare URLs, www. hosts, email addresses, and CommonMark angle autolinks work without preprocessing:

GptMarkdown(
  'Visit https://gptmarkdown.com or email hello@example.com',
)

Autolinks follow GFM trimming rules, preserve balanced parentheses, and avoid leaking surrounding Markdown into the URL. Add app-specific schemes or turn bare autolinking off when needed:

GptMarkdown(
  reply,
  autolinkSchemes: const {'myapp'},
  // autolink: false,
)

Explicit [label](url) links continue working when autolink is disabled.

๐Ÿš€ New in 1.2.0

  • Adaptive streaming reveal with split-document caching
  • GptMarkdownStyleSheet and twelve per-component style classes
  • Builders and callbacks for every major output component
  • Selectable, wrapping, baseline-aligned inline-code chips
  • InlinePattern for product-specific inline syntax
  • MarkdownScope for safe nested rendering
  • GFM and CommonMark autolinking
  • Correct RTL inline-widget ordering
  • Proportional accessibility text scaling
  • Theme and runtime configuration rebuild fixes
  • Safer malformed-Markdown and component dispatch behavior

Upgrading from 1.1.x? Read the migration guide.

๐Ÿ“š Documentation

Guide Covers
Getting started Installation, syntax, taps, LaTeX, RTL, and selection
Customization Style classes, themes, builders, and callbacks
Streaming Pacing, performance, accessibility, and limitations
Inline syntax Autolinks, mentions, channels, and scopes
Custom components Block and inline extensions
Migration Changes from 1.1.x to 1.2.0

๐Ÿ’ฌ Community

Issues and pull requests are welcome on GitHub. If the package helps your project, consider giving it a like on pub.dev or a star on GitHub.

๐Ÿ“„ License

BSD 3-Clause โ€” see LICENSE.