Skip to main content

Overview

The Markdown Decoder parses Markdown strings into AppFlowy Editor Document objects. It uses the GitHub Flavored Markdown specification and supports custom inline syntaxes and element parsers.

DocumentMarkdownDecoder

The main class for decoding Markdown to document format.

Constructor

DocumentMarkdownDecoder({
  List<CustomMarkdownParser> markdownElementParsers = const [],
  List<md.InlineSyntax> inlineSyntaxes = const [],
})

Parameters

  • markdownElementParsers (List<CustomMarkdownParser>): Custom parsers for handling specific Markdown elements. Default is an empty list.
  • inlineSyntaxes (List<md.InlineSyntax>): Custom inline syntax parsers (from the markdown package). Default is an empty list.

Methods

convert

Document convert(String input)
Converts a Markdown string to a Document object. Parameters:
  • input (String): The Markdown string to parse
Returns: Document - The parsed document Example:
final decoder = DocumentMarkdownDecoder(
  markdownElementParsers: [
    const MarkdownParagraphParserV2(),
    const MarkdownHeadingParserV2(),
    const MarkdownTodoListParserV2(),
    const MarkdownUnorderedListParserV2(),
    const MarkdownOrderedListParserV2(),
    const MarkdownBlockQuoteParserV2(),
    const MarkdownTableListParserV2(),
    const MarkdownDividerParserV2(),
    const MarkdownImageParserV2(),
  ],
);

final markdown = '''
## Hello World

This is a **bold** statement.

* Item 1
* Item 2
''';

final document = decoder.convert(markdown);

Helper Function

markdownToDocument

A convenient helper function that provides a simpler API with default parsers.
Document markdownToDocument(
  String markdown, {
  List<CustomMarkdownParser> markdownParsers = const [],
  List<md.InlineSyntax> inlineSyntaxes = const [],
})
Parameters:
  • markdown (String): The Markdown string to parse
  • markdownParsers (List<CustomMarkdownParser>): Additional custom parsers
  • inlineSyntaxes (List<md.InlineSyntax>): Additional inline syntax parsers
Returns: Document - The parsed document Example:
import 'package:appflowy_editor/appflowy_editor.dart';

// Simple usage with default parsers
final document = markdownToDocument('# Hello World\n\nWelcome!');

// With custom parsers
final document = markdownToDocument(
  markdown,
  markdownParsers: [MyCustomMarkdownParser()],
  inlineSyntaxes: [MyCustomInlineSyntax()],
);

Supported Markdown Syntax

The decoder supports GitHub Flavored Markdown including:

Block Elements

  • Headings: # H1 through ###### H6
  • Paragraphs: Regular text blocks
  • Lists:
    • Unordered: *, -, or +
    • Ordered: 1., 2., etc.
    • Nested lists with indentation
  • Todo Lists: - [x] (checked) or - [ ] (unchecked)
  • Block Quotes: > Quote text
  • Code Blocks: Fenced with triple backticks
  • Tables: Pipe-separated tables with alignment
  • Horizontal Rules: ---, ***, or ___
  • Images: ![alt text](url)

Inline Elements

  • Bold: **text** or __text__
  • Italic: *text* or _text_
  • Code: `code`
  • Links: [text](url)
  • Strikethrough: ~~text~~
  • Underline: Custom syntax support
  • Formulas: Custom inline math syntax

Example Usage

Basic Parsing

final markdown = '''
## 👋 **Welcome to** ***[AppFlowy Editor](appflowy.io)***

AppFlowy Editor is a **highly customizable** _rich-text editor_

- [x] Customizable
- [x] Test-covered
- [ ] more to come!

> Here is an example you can give a try

* Use / to insert blocks
* Select text to trigger the toolbar

1. First item
2. Second item

![Example image](path/to/image.png)
''';

final document = markdownToDocument(markdown);
print(document.toJson());

Nested Lists

final markdown = '''
# Welcome to AppFlowy

## Tasks

- Task Parent One
    - Task One + Parent
      - Task Two
    - Task Three
- Task Four

1. Numbered List
    1. Which
    2. Is
    3. Nested
2. Back to top level
''';

final document = markdownToDocument(markdown);

Formatting Rules

The decoder applies special formatting rules to handle edge cases:

Image Handling

  1. Single newline before image: Automatically adds double newline
    Text\n![image](url) → Text\n\n![image](url)
    
  2. No newline before image: Adds double newline
    Text![image](url) → Text\n\n![image](url)
    

Custom Parsers

Create custom parsers by implementing CustomMarkdownParser:
import 'package:markdown/markdown.dart' as md;

class MyCustomParser implements CustomMarkdownParser {
  const MyCustomParser();

  @override
  List<Node> transform(
    md.Node mdNode,
    List<CustomMarkdownParser> parsers,
  ) {
    // Custom parsing logic
    if (mdNode is md.Element && mdNode.tag == 'custom') {
      return [
        Node(
          type: 'custom_type',
          attributes: {...},
        )
      ];
    }
    return [];
  }
}

// Use your custom parser
final document = markdownToDocument(
  markdown,
  markdownParsers: [const MyCustomParser()],
);

Custom Inline Syntax

Add custom inline syntax support:
import 'package:markdown/markdown.dart' as md;

class CustomInlineSyntax extends md.InlineSyntax {
  CustomInlineSyntax() : super(r'\$\$(.+?)\$\$');

  @override
  bool onMatch(md.InlineParser parser, Match match) {
    // Handle the match
    final content = match[1];
    parser.addNode(md.Element.text('formula', content));
    return true;
  }
}

final document = markdownToDocument(
  'This has $$math$$ inline',
  inlineSyntaxes: [CustomInlineSyntax()],
);

Built-in Extensions

The decoder includes built-in support for:
  • FormulaInlineSyntax: Parse mathematical formulas
  • UnderlineInlineSyntax: Support underlined text

See Also

Build docs developers (and LLMs) love