PackageTrack
Sign in Get early access

flutter_md

Markdown library written in Dart. It can parse and display Markdown.

0.2.0 4.3K downloads/mo #4073 most downloaded on pub.dev DoctorinaAI/md

What this package is like to depend on

Last release 18 days ago

05 Aug 2026

Ships unpredictably

gaps range from 8 days to 10 months

Nearly every release is documented

notes for 9 of 9 stable releases

Nothing withdrawn

no release was ever pulled

1 years old

9 releases · first in 2025

4 releases in the last 12 months

see the full history below

Release timeline

9 releases · Jun 2025 to Aug 2026
2026
Release Pre-release

Releases

latest 9
  1. 0.2.0 05 Aug 2026
    Release notes

    0.2.0

    Upgrading from 0.0.x? See the
    migration guide. 0.2.x is almost entirely
    backward compatible — the only required code change is a new alert branch
    for direct MD$Block.map / switch callers.

    • ADDED: Opt-in, dependency-free syntax highlighting for fenced code blocks
      (65+ languages, GitHub light/dark themes). Assign a SyntaxHighlighter to the
      new MarkdownThemeData.highlighter field; the default (unset) renders code as
      plain monospace, so existing usage is unchanged. New public API on
      package:flutter_md/highlight.dart: SyntaxHighlighter, MarkdownHighlighter,
      CodeHighlightTheme, Grammar, GrammarToken, compileHighlightPattern
      (SyntaxHighlighter / CodeHighlightTheme are also re-exported from the main
      entrypoint). Each language is its own library
      (package:flutter_md/highlight/<lang>.dart, e.g. HighlightDart.grammar) with
      no central registry, so importing one never references the others and unused
      grammars tree-shake away — a Dart-only app adds ~0 beyond the engine; all 65
      add ~62 KB gzipped. HighlightThemes.githubDark / githubLight
      (highlight/themes.dart) provide ready themes; allHighlightLanguages
      (highlight/all.dart) is a convenience registry of every grammar for
      demos/tooling (it references all languages, so unused ones can no longer
      tree-shake away). The highlighter only partitions text — never edits it — so
      selection and copy stay aligned. Grammars are generated by
      tool/highlight_codegen (adapted from Prism, MIT).
    • ADDED: Cross-block and cross-widget text selection. A
      MarkdownSelectionController anchors the selection on the immutable model, so
      it spans multiple blocks and multiple MarkdownWidgets and survives list
      disposal (e.g. chat scrolling). New public API: MarkdownSelectionController,
      MarkdownSelectionScope, MarkdownSelectionGroup, MarkdownPosition,
      MarkdownSelection, MarkdownDocumentRef, MarkdownSelectedContent
      (+ document/block), MarkdownSelectionFormatter /
      MarkdownPlainTextFormatter / MarkdownMarkupFormatter,
      MarkdownReconciliationPolicy, MarkdownSelectionSurface,
      markdownBlockRenderedText, and
      SelectableBlockPainter / SelectableTextBlock.
    • ADDED: StreamingMarkdownParser, an incremental parser for streaming
      sources such as LLM token output. It freezes completed blocks (a block ends at
      a blank line, outside any open code fence) so only the still-growing tail is
      re-parsed as tokens arrive — turning the O(N²) cost of re-parsing the whole
      buffer on every token into roughly O(tail) (3–14× faster on a full message
      stream in benchmark/streaming_benchmark.dart). parser.add(chunk) returns
      the growing Markdown, always identical block-for-block to
      Markdown.fromString(everythingSoFar), and a Stream<String>.toMarkdown()
      extension wires it into a stream transform. Pass a configured MarkdownDecoder
      (e.g. inlineMath: true) to match Markdown.fromString. The batch
      MarkdownDecoder hot path is byte-for-byte unchanged.
    • ADDED: MarkdownMarkupFormatter, a built-in "Copy as Markdown" formatter.
      Pass it to getText() (or set controller.formatter) to reconstruct Markdown
      structure on copy — heading #s, nested list markers with task checkboxes,
      blockquote/alert > prefixes, fenced code and pipe tables — for blocks the
      selection covers in full; partially-selected boundary blocks fall back to the
      plain sliced text so nothing outside the selection is emitted. The default
      copy behaviour is unchanged (MarkdownPlainTextFormatter).
    • ADDED: MarkdownWidget gains optional documentId and controller
      parameters (resolved from the ambient scope). Backward compatible: a widget
      with no documentId is inert.
    • ADDED: Lists and tables are now interactively selectable. A new
      MultiPainterSelectable mixin (+ SelectableFragment) maps pointer positions
      and highlight boxes across the many TextPainters of a list's items or a
      table's cells, so a drag can start or end inside a list item or table cell and
      the copied text keeps the \n / \t separators of markdownBlockRenderedText.
    • ADDED: Keyboard shortcuts and a context toolbar on MarkdownSelectionScope,
      mirroring SelectableRegion/SelectableText. When focused: Ctrl/Cmd+C
      copies, Ctrl/Cmd+A selects all, Shift+arrows extend by character / word /
      line / document (and vertically by geometry), Esc clears. Right-click
      (desktop) / long-press (mobile) shows an adaptive Copy / Select-all toolbar.
      The scope is now a StatefulWidget with a public MarkdownSelectionScopeState
      (copySelection / selectAll / clearSelection / showToolbar /
      hideToolbar / contextMenuButtonItems / contextMenuAnchors). New
      customization params: focusNode, enabled, selectionColor,
      contextMenuBuilder, magnifierConfiguration, selectionControls,
      onSelectionChanged. New controller ops: selectionColor,
      globalSelectionRects, moveSelectionEdgeToGlobal, and the
      extendSelectionBy* family; MarkdownPosition.copyWith.
    • ADDED: Native selection handles and a magnifier on touch platforms,
      driven by Flutter's SelectionOverlay. Selection endpoints push
      LeaderLayers from the render objects so the handles follow the content as it
      scrolls (and across multiple MarkdownWidgets); dragging a handle adjusts the
      selection and shows the platform magnifier. Handles/magnifier respect the
      platform (selectionControls, magnifierConfiguration) and are absent on
      desktop, matching SelectableText. New surface geometry:
      localSelectionRects, setSelectionHandleLayers, repaintSelection, and
      MarkdownSelectionController.selectionHandleEndpoints /
      MarkdownHandleEndpoints.
    • ADDED: Word- and block-granular selection gestures. Double-click/tap
      selects the word under the pointer, triple-click/tap selects the whole block,
      a single click collapses (clears) the selection, and Shift-click extends it.
      Dragging after a double/triple click keeps word/block granularity; a touch
      long-press grabs the whole word (then extends by word), and a touch
      double-tap selects the word and pops the toolbar. Word boundaries use the
      platform word segmentation (TextPainter.getWordBoundary), so double-click
      keeps intra-word punctuation like apostrophes (can't). New controller ops:
      selectWordAtGlobal, selectBlockAtGlobal, wordSelectionAt,
      blockSelectionAt, extendSelectionGranular, and wordRangeIn; new surface
      geometry MarkdownSelectionSurface.wordBoundaryForGlobal.
    • ADDED: Mouse cursor feedback — a MarkdownWidget shows the click (hand)
      cursor over actionable links, the text (I-beam) cursor while it participates
      in a selection controller, and otherwise the default cursor.
    • CHANGED: MarkdownWidget's render object now draws the selection
      highlight outside the cached content Picture and becomes a repaint boundary
      when selectable, so selection/drag repaints do not rebuild the glyph cache.
      The highlight color is now customizable via the controller / scope. The
      highlight is painted on top of (rather than beneath) the glyphs, so a
      translucent selection stays visible over opaque backgrounds — code fences,
      inline code, and ==marked== spans.
    • EXAMPLE: Reworked the demo tabs — a longer, richer chat (tables, code,
      nested/task lists, alerts, math, token-by-token streaming with a typing
      indicator, Select-all/Clear) and a Selection tab that spans every block type.

    0.1.0

    • ADDED: GitHub-style alert blocks (> [!NOTE], > [!TIP], > [!IMPORTANT],
      > [!WARNING], > [!CAUTION]) via the new MD$Alert block and MD$AlertType.
    • ADDED: GitHub task-list items (- [ ] / - [x]) via MD$ListItem.checked
      and MD$ListItem.isTask, rendered with a checkbox.
    • ADDED: Table column alignment (:---, :--:, ---:) captured on
      MD$Table.alignments and applied when rendering.
    • ADDED: linkStyle on MarkdownThemeData to customize link text styling
      (thanks @inamhusain, #22).
    • ADDED: Per-type alert accent colors via MarkdownThemeData.alertColors
      and alertColorFor.
    • ADDED: Opt-in $...$ inline LaTeX math conversion to Unicode, disabled
      by default
      . Enable with MarkdownDecoder(inlineMath: true) or
      Markdown.fromString(text, inlineMath: true). Supports LaTeX commands
      (\alpha, \rightarrow, ...), superscripts/subscripts (x^2, H_2O,
      x^{10}), is code-span and code-block safe, and preserves currency ($5).
      The command table is configurable via mathReplacements (extend the
      exported kMarkdownMathCommands). Originally proposed in #21 by
      @ibragimov05.
    • FIXED: \$ is now a recognized backslash escape, producing a literal
      dollar sign (and opting a $...$ run out of math conversion).
    • CHANGED: Thematic breaks now support *** and ___ (and spaced variants
      like - - -), and no longer greedily consume text after ---.
    • CHANGED: ~~~ fenced code blocks are now recognized in addition to ```.
    • FIXED: Emphasis no longer leaks to the end of the line for stray or
      unterminated markers (e.g. 5 * 6 = 30, **bold never closed).
    • FIXED: Intraword underscores are no longer treated as emphasis
      (e.g. snake_case, object_id are preserved).
    • FIXED: ATX headings require a space after #; #hashtag and 7+ #
      are no longer headings, and trailing # sequences are stripped.
    • FIXED: Emphasis surrounding a link/image is now merged onto the link span.
    • FIXED: Link/image targets support <url> and single-quoted titles.
    • FIXED: MarkdownThemeData.copyWith no longer drops builder and onLinkTap.
    • BREAKING: MD$Block.map/maybeMap gained an alert branch for the new
      MD$Alert block type.
    • PERFORMANCE: Rewrote the parser hot path — a single-span fast path for
      plain text, first-code-unit guards that keep regexes off paragraph lines,
      hand-rolled list-line and link-target parsing (removing per-line / per-link
      RegExp allocation), lazy link-extraction gated on [, and a range-copy
      escape rebuild (no more per-character hash-set lookups). Together with math
      now being opt-in, the default parse path is roughly 45% faster across
      representative workloads (links −68%, lists −61%, escapes −68%). Output is
      byte-identical, guarded by a golden snapshot test.
    • TESTS: Added a golden characterization snapshot, a corner-case regression
      suite, span-offset invariants, and unit tests for the node model, theme, and
      widget; wired every test file into test/unit_test.dart so CI runs the full
      suite (370+ tests, previously only a fraction ran). parser.dart,
      nodes.dart, markdown.dart, theme.dart, and widget.dart are now at
      ~100% line coverage.
    • ADDED: benchmark/parser_benchmark.dart (a multi-scenario
      benchmark_harness suite) and benchmark/compare.dart (a low-noise
      before/after comparison tool).
    • DOCS: Documented alerts, task lists, table alignment, thematic-break
      variants, and opt-in inline math in the README.
    Open source →
    Release notes

    Upgrading from 0.0.x? See the migration guide. 0.2.x is almost entirely backward compatible — the only required code change is a new alert branch for direct MD$Block.map / switch callers.

    • ADDED: Opt-in, dependency-free syntax highlighting for fenced code blocks (65+ languages, GitHub light/dark themes). Assign a SyntaxHighlighter to the new MarkdownThemeData.highlighter field; the default (unset) renders code as plain monospace, so existing usage is unchanged. New public API on package:flutter_md/highlight.dart: SyntaxHighlighter, MarkdownHighlighter, CodeHighlightTheme, Grammar, GrammarToken, compileHighlightPattern (SyntaxHighlighter / CodeHighlightTheme are also re-exported from the main entrypoint). Each language is its own library (package:flutter_md/highlight/<lang>.dart, e.g. HighlightDart.grammar) with no central registry, so importing one never references the others and unused grammars tree-shake away — a Dart-only app adds ~0 beyond the engine; all 65 add ~62 KB gzipped. HighlightThemes.githubDark / githubLight (highlight/themes.dart) provide ready themes; allHighlightLanguages (highlight/all.dart) is a convenience registry of every grammar for demos/tooling (it references all languages, so unused ones can no longer tree-shake away). The highlighter only partitions text — never edits it — so selection and copy stay aligned. Grammars are generated by tool/highlight_codegen (adapted from Prism, MIT).
    • ADDED: Cross-block and cross-widget text selection. A MarkdownSelectionController anchors the selection on the immutable model, so it spans multiple blocks and multiple MarkdownWidgets and survives list disposal (e.g. chat scrolling). New public API: MarkdownSelectionController, MarkdownSelectionScope, MarkdownSelectionGroup, MarkdownPosition, MarkdownSelection, MarkdownDocumentRef, MarkdownSelectedContent (+ document/block), MarkdownSelectionFormatter / MarkdownPlainTextFormatter / MarkdownMarkupFormatter, MarkdownReconciliationPolicy, MarkdownSelectionSurface, markdownBlockRenderedText, and SelectableBlockPainter / SelectableTextBlock.
    • ADDED: StreamingMarkdownParser, an incremental parser for streaming sources such as LLM token output. It freezes completed blocks (a block ends at a blank line, outside any open code fence) so only the still-growing tail is re-parsed as tokens arrive — turning the O(N²) cost of re-parsing the whole buffer on every token into roughly O(tail) (3–14× faster on a full message stream in benchmark/streaming_benchmark.dart). parser.add(chunk) returns the growing Markdown, always identical block-for-block to Markdown.fromString(everythingSoFar), and a Stream<String>.toMarkdown() extension wires it into a stream transform. Pass a configured MarkdownDecoder (e.g. inlineMath: true) to match Markdown.fromString. The batch MarkdownDecoder hot path is byte-for-byte unchanged.
    • ADDED: MarkdownMarkupFormatter, a built-in "Copy as Markdown" formatter. Pass it to getText() (or set controller.formatter) to reconstruct Markdown structure on copy — heading #s, nested list markers with task checkboxes, blockquote/alert > prefixes, fenced code and pipe tables — for blocks the selection covers in full; partially-selected boundary blocks fall back to the plain sliced text so nothing outside the selection is emitted. The default copy behaviour is unchanged (MarkdownPlainTextFormatter).
    • ADDED: MarkdownWidget gains optional documentId and controller parameters (resolved from the ambient scope). Backward compatible: a widget with no documentId is inert.
    • ADDED: Lists and tables are now interactively selectable. A new MultiPainterSelectable mixin (+ SelectableFragment) maps pointer positions and highlight boxes across the many TextPainters of a list's items or a table's cells, so a drag can start or end inside a list item or table cell and the copied text keeps the \n / \t separators of markdownBlockRenderedText.
    • ADDED: Keyboard shortcuts and a context toolbar on MarkdownSelectionScope, mirroring SelectableRegion/SelectableText. When focused: Ctrl/Cmd+C copies, Ctrl/Cmd+A selects all, Shift+arrows extend by character / word / line / document (and vertically by geometry), Esc clears. Right-click (desktop) / long-press (mobile) shows an adaptive Copy / Select-all toolbar. The scope is now a StatefulWidget with a public MarkdownSelectionScopeState (copySelection / selectAll / clearSelection / showToolbar / hideToolbar / contextMenuButtonItems / contextMenuAnchors). New customization params: focusNode, enabled, selectionColor, contextMenuBuilder, magnifierConfiguration, selectionControls, onSelectionChanged. New controller ops: selectionColor, globalSelectionRects, moveSelectionEdgeToGlobal, and the extendSelectionBy* family; MarkdownPosition.copyWith.
    • ADDED: Native selection handles and a magnifier on touch platforms, driven by Flutter's SelectionOverlay. Selection endpoints push LeaderLayers from the render objects so the handles follow the content as it scrolls (and across multiple MarkdownWidgets); dragging a handle adjusts the selection and shows the platform magnifier. Handles/magnifier respect the platform (selectionControls, magnifierConfiguration) and are absent on desktop, matching SelectableText. New surface geometry: localSelectionRects, setSelectionHandleLayers, repaintSelection, and MarkdownSelectionController.selectionHandleEndpoints / MarkdownHandleEndpoints.
    • ADDED: Word- and block-granular selection gestures. Double-click/tap selects the word under the pointer, triple-click/tap selects the whole block, a single click collapses (clears) the selection, and Shift-click extends it. Dragging after a double/triple click keeps word/block granularity; a touch long-press grabs the whole word (then extends by word), and a touch double-tap selects the word and pops the toolbar. Word boundaries use the platform word segmentation (TextPainter.getWordBoundary), so double-click keeps intra-word punctuation like apostrophes (can't). New controller ops: selectWordAtGlobal, selectBlockAtGlobal, wordSelectionAt, blockSelectionAt, extendSelectionGranular, and wordRangeIn; new surface geometry MarkdownSelectionSurface.wordBoundaryForGlobal.
    • ADDED: Mouse cursor feedback — a MarkdownWidget shows the click (hand) cursor over actionable links, the text (I-beam) cursor while it participates in a selection controller, and otherwise the default cursor.
    • CHANGED: MarkdownWidget's render object now draws the selection highlight outside the cached content Picture and becomes a repaint boundary when selectable, so selection/drag repaints do not rebuild the glyph cache. The highlight color is now customizable via the controller / scope. The highlight is painted on top of (rather than beneath) the glyphs, so a translucent selection stays visible over opaque backgrounds — code fences, inline code, and ==marked== spans.
    • EXAMPLE: Reworked the demo tabs — a longer, richer chat (tables, code, nested/task lists, alerts, math, token-by-token streaming with a typing indicator, Select-all/Clear) and a Selection tab that spans every block type.
    Open source →
  2. 0.0.8 09 Oct 2025
    Release notes

    What's Changed

    Full Changelog: 0.0.7...0.0.8

    Open source →
    Release notes
    • CHANGED: New table render
    • FIXED: Invalidate and relayout render object after system fonts changed.
    Open source →
  3. 0.0.7 10 Sep 2025
    Release notes

    V 0.0.7 (#13)

    * feat: support theming

    * feat: add divider color to MarkdownThemeData and update BlockPainter$Quote

    * fix: Inline code incorrectly parses inner markdown syntax (#10)

    * fix: No indentation after line breaks within list item (#4)

    * chore: update version to 0.0.7 and enhance changelog with recent fixes and features

    Open source →
    Release notes
    • FIXED: Preserved indentation on line breaks within list items [#4].
    • FIXED: Inline code no longer processes inner Markdown syntax [#10].
    • CHANGED: Improved theme support.
    • ADDED: Dark mode support in the example app.
    Open source →
  4. 0.0.6 02 Sep 2025
    Release notes
    • FIXED: Fixed escaping of special characters. [#6]
    Open source →
    Release notes
    • FIXED: Fixed escaping of special characters. [#6]
    Open source →
  5. 0.0.5 16 Jul 2025
    Release notes
    • FIXED: Fixed parsing url such as [text](https://domain.com/path(with)brackets).
    Open source →
    Release notes
    • FIXED: Fixed parsing url such as [text](https://domain.com/path(with)brackets).
    Open source →
  6. 0.0.4 08 Jul 2025
    Release notes
    • CHANGED: Improved link tap handling.
    Open source →
    Release notes
    • CHANGED: Improved link tap handling.
    Open source →
  7. 0.0.3 20 Jun 2025
    Release notes
    • FIXED: Links inside lists now work correctly.
    Open source →
    Release notes
    • FIXED: Links inside lists now work correctly.
    Open source →
  8. 0.0.2 19 Jun 2025
    Release notes

    ADDED: All field in MarkdownThemeData() are now optional.
    ADDED: MarkdownThemeData{}.headingStyleFor method to customize heading styles.
    FIXED: Remove clipping for canvas. Fixes one line text trim at browsers.
    FIXED: Correctly apply styles to text in blocks.

    Open source →
    Release notes
    • ADDED: All field in MarkdownThemeData() are now optional.
    • ADDED: MarkdownThemeData{}.headingStyleFor method to customize heading styles.
    • FIXED: Remove clipping for canvas. Fixes one line text trim at browsers.
    • FIXED: Correctly apply styles to text in blocks.
    Open source →
  9. 0.0.1 18 Jun 2025
    Release notes
    • ADDED: Initial release with basic functionality.
    Open source →

Every package, every release, already written down.

The archive is open and free. Watching your own project is what we are building next.

Browse the archive