flutter_smooth_markdown 0.8.1 copy "flutter_smooth_markdown: ^0.8.1" to clipboard
flutter_smooth_markdown: ^0.8.1 copied to clipboard

High-performance Flutter markdown renderer and editor with syntax highlighting, LaTeX math, tables, footnotes, SVG images, and real-time streaming support.

Flutter Smooth Markdown #

pub package popularity likes GitHub stars GitHub forks GitHub issues GitHub license Flutter Dart

A high-performance Flutter markdown renderer with syntax highlighting, LaTeX math, tables, footnotes, SVG images, Mermaid diagrams, and real-time streaming support.

Features #

Category Features
Rendering AST-based parsing, syntax highlighting, real-time streaming, text selection
Editing Formatted/source/preview/split editor, formatting toolbar, slash commands, wikilinks, find
Markdown Headers (with inline formatting), lists, tables, code blocks, blockquotes, links, images
Math & Charts LaTeX formulas, Mermaid diagrams (flowcharts, Gantt, Kanban, Timeline, Radar, XY Chart, pie, sequence)
Extras Footnotes, SVG support, collapsible sections, task lists
Theming Light/dark modes, GitHub/VS Code presets, custom themes
Plugins Mentions, hashtags, emojis, AI chat blocks (thinking, artifacts)

Demo #

Main Interface Code Blocks LaTeX Math
Main Interface Code Blocks LaTeX Math
Real-time Streaming

Run the example app: cd example && flutter run

Run the editor preview directly in Chrome: cd example && flutter run -d chrome -t lib/editor_preview_main.dart

The full example app also exposes the editor from the sidebar in example/lib/editor_demo.dart.

Quick Start #

Installation #

dependencies:
  flutter_smooth_markdown: ^0.8.0
flutter pub get

Basic Usage #

import 'package:flutter_smooth_markdown/flutter_smooth_markdown.dart';

SmoothMarkdown(
  data: '# Hello Markdown\n\nThis is **bold** and *italic*.',
  styleSheet: MarkdownStyleSheet.light(),
  onTapLink: (url) => print('Tapped: $url'),
)

Selectable Text #

SmoothMarkdown(
  data: markdownText,
  selectable: true,
  onTapImage: (url, alt, title) {
    showImagePreview(context, url);
  },
)

Selection handles work across text and non-text blocks (images, tables, etc.). Copied content is automatically cleaned.

Markdown Editor #

import 'package:flutter_smooth_markdown/flutter_smooth_markdown_editor.dart';

final editorController = MarkdownEditorController(
  text: '# Scratch note',
  historyLimit: 200,
);

SmoothMarkdownEditor(
  controller: editorController,
  mode: MarkdownEditorMode.formatted,
  wikilinkSuggestions: const ['Daily Notes', 'Project Plan'],
  capabilities: const MarkdownEditorCapabilities(
    disabledCommands: {
      MarkdownEditorCommand.mermaidDiagram,
      MarkdownEditorCommand.blockMath,
    },
  ),
  toolbarCommands: const [
    MarkdownEditorCommand.bold,
    MarkdownEditorCommand.italic,
    MarkdownEditorCommand.link,
    MarkdownEditorCommand.image,
    MarkdownEditorCommand.codeBlock,
    MarkdownEditorCommand.table,
  ],
  toolbarTrailing: [
    IconButton(
      tooltip: 'Save',
      icon: const Icon(Icons.save_outlined),
      onPressed: () {
        saveDraft(editorController.text);
        editorController.markSaved();
      },
    ),
  ],
  onChanged: (markdown) => saveDraft(markdown),
  onCommand: (command) => analytics.track('markdown_command', command.name),
  onSelectionChanged: (selection) => updateSelectionState(selection),
  onTapWikilink: (target) => openNote(target),
  onExportMarkdown: (markdown) => saveMarkdownFile(markdown),
)

SmoothMarkdownEditor keeps Markdown source as the document of record and renders the preview with SmoothMarkdown. It includes Scratch-inspired editor controls: formatting commands, Cmd/Ctrl+B, Cmd/Ctrl+I, Cmd/Ctrl+K, Cmd/Ctrl+F, Cmd/Ctrl+Shift+M, Cmd/Ctrl+Shift+Enter, / commands, [[wikilink]] autocomplete, formatted block editing, code-block language selection, Mermaid preview/source toggling, block math editing, copy-as-Markdown/plain-text/HTML, Markdown import/export callbacks, focus mode, and source, preview, or split layouts.

Host apps can treat MarkdownEditorController as the stable integration point: use text for the Markdown source, isDirty/markSaved() for save state, selection/getSelectionMarkdown() for source selections, insertMarkdown() or replaceSelection() for integrations, undo()/redo() for custom UI, and the table helpers (replaceTableCellText, insertTableRowAfter, insertTableColumnBefore, setTableColumnAlignment, etc.) for host table controls. Use controlled mode + onModeChanged when the app owns editor layout, MarkdownEditorCapabilities to disable built-in commands, toolbarCommands to hide or reorder the built-in toolbar buttons, toolbarLeading/toolbarTrailing to add host actions, toolbarBuilder to wrap or replace the toolbar, enableKeyboardShortcuts to turn off built-in shortcuts, and onShortcut to intercept keys before the editor handles them.

Editor chrome can be styled without forking the widget. Pass editorTheme: MarkdownEditorThemeData(...) to one editor, or install the same theme globally through ThemeData.extensions. The editor theme covers toolbar colors, active button states, search/suggestion panels, selection/drop highlights, block chrome, table grid/header/selection colors, source and preview decorations, source text style, radii, and content padding.

Large-document integrations can observe lightweight editor telemetry with onPerformanceSnapshot. The snapshot reports source length, semantic block count, formatted segment count, formatted segment cache hits, retained formatted segment keys, mode, IME composing state, search match count, and visible suggestion panels. This is intended for host-side logging, perf dashboards, or debug overlays without reaching into private editor state.

Custom block integrations can pair parser plugins with editor builders. Provide customBlockBuilder to render unsupported/custom blocks in formatted mode and customBlockEditorBuilder to supply an editor that calls replaceMarkdown(), finishEditing(), or delete() from the supplied context. This lets host apps edit callouts, embeds, database cards, or app-specific directives without forking the core editor.

File-oriented editor actions are intentionally callback-based so apps can choose their own desktop, mobile, or web integrations. When callbacks are omitted, Export Markdown copies Markdown to the clipboard, Print as PDF copies the generated HTML fallback, Import Markdown is hidden, and image insertion uses the built-in URL dialog. Provide onExportMarkdown, onExportPdf, onImportMarkdown, and onPickImage to connect file pickers, print/PDF packages, asset uploads, or platform share sheets. Use onImagePickEvent to surface picking, cancellation, insertion, and failure states in host UI, such as upload progress banners or retry affordances.

The core package does not ship default file picker, printing, share, upload, or platform image picker adapters; keep those integrations in the host app and route them through the callbacks above. flutter_smooth_markdown_editor.dart is the stable editor-only entry point for app integrations. Lower-level document model, codec, and transaction helpers are still evolving; import the explicit experimental entry point when an integration needs those APIs and pin compatible package versions.

import 'package:flutter_smooth_markdown/flutter_smooth_markdown_editor_experimental.dart';

Programmatic Selection #

When selectable: true, the content is wrapped in a SmoothSelectionRegion (a thin SelectableRegion adapter). Pass a selectionController to drive selection programmatically:

final controller = SmoothSelectionController();

SmoothMarkdown(
  data: markdownText,
  selectable: true,
  selectionController: controller,
)

// Later — enter selection mode with handles + toolbar:
controller.selectAll(SelectionChangedCause.toolbar);

// Or select text around a press position:
controller.selectParagraphAt(details.globalPosition);

The selection rule lives in your application code. For example, a chat bubble menu can choose paragraph selection while an editor toolbar chooses select-all:

void handleSelectText(Offset pressPosition) {
  switch (selectionMode) {
    case SelectionMode.word:
      controller.selectWordAt(pressPosition);
      return;
    case SelectionMode.paragraph:
      controller.selectParagraphAt(pressPosition);
      return;
    case SelectionMode.message:
      controller.selectAll(SelectionChangedCause.toolbar);
      return;
  }
}

For lower-level control, SmoothSelectionController exposes the underlying SelectionContainer + SelectionEvent machinery:

// Clear the current selection (hides handles + toolbar):
controller.clearSelection();

// Dispatch an arbitrary SelectionEvent straight to the SelectionContainer
// (fans out to every text selectable). Does not drive the overlay by itself.
controller.dispatchEvent(const SelectAllSelectionEvent());

// Reach the SelectionRegistrar collecting the text selectables.
final registrar = controller.registrar;

contextMenuBuilder (if provided) now receives a SmoothSelectionRegionState, giving the menu access to dispatchEvent, registrar, contextMenuButtonItems, and contextMenuAnchors.

selectableRegionKey is still available for advanced integrations that need direct access to SmoothSelectionRegionState.

Migration (minor breaking): selectableRegionKey is now typed GlobalKey<SmoothSelectionRegionState> (was GlobalKey<SelectableRegionState>), and contextMenuBuilder's second parameter is now SmoothSelectionRegionState. Rename the type and the new methods become available; existing calls (selectAll, contextMenuButtonItems, contextMenuAnchors) work unchanged. New code should prefer selectionController.

Streaming (Real-time) #

StreamMarkdown(
  stream: yourMarkdownStream,
  styleSheet: MarkdownStyleSheet.dark(),
)

Enhanced Components #

final renderer = MarkdownRenderer(styleSheet: MarkdownStyleSheet.light());

renderer.builderRegistry
  ..register('code_block', const EnhancedCodeBlockBuilder())
  ..register('blockquote', const EnhancedBlockquoteBuilder())
  ..register('link', const EnhancedLinkBuilder())
  ..register('header', const EnhancedHeaderBuilder());

final nodes = MarkdownParser().parse(markdownText);
final widget = renderer.render(nodes);

Theming #

// Built-in themes
MarkdownStyleSheet.light()
MarkdownStyleSheet.dark()
MarkdownStyleSheet.github(brightness: Brightness.light)
MarkdownStyleSheet.vscode(brightness: Brightness.dark)

// From Flutter theme
MarkdownStyleSheet.fromTheme(Theme.of(context))

// Custom
MarkdownStyleSheet.light().copyWith(
  h1Style: TextStyle(fontSize: 32, fontWeight: FontWeight.bold),
  linkStyle: TextStyle(color: Colors.blue),
)

Plugins #

// Custom syntax plugins
final registry = ParserPluginRegistry();
registry.register(const MentionPlugin());    // @username
registry.register(const HashtagPlugin());    // #topic
registry.register(const EmojiPlugin());      // :smile:

final parser = MarkdownParser(plugins: registry);

AI Chat Plugins #

registry.register(const ThinkingPlugin());   // <thinking>...</thinking>
registry.register(const ArtifactPlugin());   // <artifact>...</artifact>
registry.register(const ToolCallPlugin());   // <tool_use>...</tool_use>

Mermaid Diagrams #

MermaidDiagram(
  code: '''
  graph TD
    A[Start] --> B{Decision}
    B -->|Yes| C[Action]
    B -->|No| D[End]
  ''',
  style: MermaidStyle.dark(),
)

Supports: Flowcharts, Sequence Diagrams, Pie Charts, Gantt Charts, Kanban Boards, Timeline Diagrams, Radar Charts, XY Charts

XY Chart Example #

MermaidDiagram(
  code: '''
  xychart-beta
    title "Sales Revenue"
    x-axis [Q1, Q2, Q3, Q4]
    y-axis "Revenue" 0 --> 100
    bar [23, 45, 67, 89]
    line [20, 50, 60, 85]
  ''',
)

Radar Chart Example #

MermaidDiagram(
  code: '''
  radar-beta
    title Skills Assessment
    axis Programming, Design, Communication, Management, Innovation
    curve Alice{5, 3, 4, 2, 4}
    curve Bob{3, 5, 3, 4, 3}
    showLegend true
    max 5
    graticule polygon
  ''',
)

Markdown Syntax #

Text Formatting
**Bold** or __Bold__
*Italic* or _Italic_
~~Strikethrough~~
`Inline code`
Lists & Tasks
- Unordered item
1. Ordered item
- [ ] Task
- [x] Completed task
Code Blocks
```dart
void main() {
  print('Hello, World!');
}
```
Tables
| Header 1 | Header 2 |
|----------|----------|
| Cell 1   | Cell 2   |
Math (LaTeX)
Inline: $E = mc^2$

Block:
$$
\int_{a}^{b} f(x) dx = F(b) - F(a)
$$
Footnotes
Text with footnote[^1].

[^1]: Footnote content.
Collapsible Sections
<details>
<summary>Click to expand</summary>
Hidden content here.
</details>

Use Cases #

  • Documentation apps with code examples
  • Chat applications with rich text
  • Note-taking apps
  • Educational platforms with LaTeX
  • AI chat interfaces with streaming

Documentation #

Document Description
Plugin System Custom parser plugins
Theme System Theming guide
Enhanced Components Rich UI components
Architecture System architecture

Roadmap #

Completed: Core parser, renderer, themes, streaming, math, tables, footnotes, SVG, plugins, Mermaid diagrams, AI chat plugins, i18n (6 languages)

In Progress: Performance optimization, API documentation

Planned: More themes, advanced tables, accessibility

Contributing #

Contributions welcome! Please read our guidelines before submitting PRs.

License #

MIT License


Made with love for the Flutter community.

9
likes
140
points
3.25k
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

High-performance Flutter markdown renderer and editor with syntax highlighting, LaTeX math, tables, footnotes, SVG images, and real-time streaming support.

Repository (GitHub)
View/report issues
Contributing

Topics

#markdown #editor #renderer #syntax-highlighting #mermaid

License

MIT (license)

Dependencies

cached_network_image, flutter, flutter_highlight, flutter_math_fork, flutter_svg, highlight

More

Packages that depend on flutter_smooth_markdown