Markdown and LaTeX rendering for Flutter, built for AI chat output.
| Guide | Read it when |
|---|---|
| Getting started | You are adding the package to an app |
| Customization | You want it to look like your app |
| Streaming and incremental rendering | You are rendering a reply as it generates or tuning performance |
| Inline syntax | You need @mention, #channel, :emoji: or autolinks |
| Custom components | Styles and builders are not enough |
| Rendering architecture | You are registering a block extension or working out which pipeline ran |
GptMarkdown options |
You need a constructor-default reference |
| Testing | Your widget tests do not find what you expect |
| Migration | You are upgrading, or want what the next release changes |
| Comparison with other renderers | You are choosing between this and another Markdown package |
| Performance baseline | You are comparing revisions of this package and need the cold first-paint record |
| Native rendering measurements | You want profile-mode numbers rather than debug-VM ones |
[!NOTE] Representative code from these guides is compiled by the test suite (
test/docs/snippets_test.dart). It covers the public option and builder signatures; prose, links and examples are also checked during review.Numbers quoted as measurements come from recorded runs, not estimates — from the tests in
test/, or from the benchmark harness the comparison and performance guides describe.
Two ways to change what you see, and they never overlap:
| Use it for | Example | |
|---|---|---|
| Style object | Appearance — colours, sizes, padding, fonts | BlockQuoteStyle(barWidth: 4) |
| Builder | Structure — replace the widget entirely | blockQuoteBuilder: … |
Every component supports both.
[!TIP] If you are reaching for a builder to change a colour, stop — there is a style field for it. Builders lose the default structure, and with it every future improvement to that component.
WidgetSpan nested inside another placeholder does not paint on iOS.
The default link is text, so this only bites when the link itself is a widget
— the deprecated linkBuilder, or an inlineLinkBuilder returning
details.asWidgetSpan(...). InlinePattern already excludes link labels; a
MarkdownComponent subclass has to declare scopes to opt out. See
inline syntax.find.text rarely finds Markdown text — prose renders as spans inside
one paragraph widget. It does reach content that renders as its own widget,
such as a code block. See testing.