Skip to main content

Overview

The HTML plugin enables bidirectional conversion between HTML and AppFlowy Editor documents. It supports rich text formatting, semantic HTML elements, and CSS inline styles.

Installation

The HTML plugin is included with AppFlowy Editor:
import 'package:appflowy_editor/appflowy_editor.dart';

Importing HTML

Basic Usage

Convert HTML to an AppFlowy document:
final html = '<h1>Hello World</h1><p>Welcome to <strong>AppFlowy</strong>!</p>';
final document = htmlToDocument(html);
final editorState = EditorState(document: document);

With Custom Decoders

Add custom element parsers for special HTML elements:
final document = htmlToDocument(
  html,
  customDecoders: {
    'custom-element': (element, parseDelta) {
      // Return an iterable of Node objects
      return [paragraphNode(text: element.text)];
    },
  },
);

Supported HTML Elements

The decoder automatically handles:

Block Elements

  • Headings: <h1> through <h6>
  • Paragraphs: <p>
  • Lists: <ul>, <ol>, <li>
  • Block quotes: <blockquote>
  • Tables: <table>, <tr>, <td>, <th>
  • Dividers: <hr>
  • Images: <img>

Inline Elements

  • Bold: <b>, <strong>
  • Italic: <i>, <em>
  • Underline: <u>
  • Strikethrough: <del>, <s>
  • Code: <code>
  • Links: <a href="...">
  • Spans: <span> (with style attributes)
  • Mark: <mark>

CSS Inline Styles

The decoder parses these CSS properties from style attributes:
  • font-weight: Bold text (values: bold or >= 500)
  • font-style: Italic text (italic)
  • text-decoration: Underline and strikethrough
  • background-color: Text highlight color
  • color: Text color
  • text-align: Text alignment

Exporting to HTML

Basic Usage

Convert an AppFlowy document to HTML:
final document = editorState.document;
final html = documentToHTML(document);

With Custom Parsers

Handle custom node types during export:
final html = documentToHTML(
  document,
  customParsers: [
    MyCustomHTMLNodeParser(),
  ],
);

Implementation Details

HTML Codec

The plugin uses a Codec<Document, String> implementation (from /lib/src/plugins/html/html_document.dart:45-63):
class AppFlowyEditorHTMLCodec extends Codec<Document, String> {
  const AppFlowyEditorHTMLCodec({
    this.encodeParsers = const [],
    this.customDecoders = const {},
  });

  final List<HTMLNodeParser> encodeParsers;
  final Map<String, ElementParser> customDecoders;

  @override
  Converter<String, Document> get decoder => DocumentHTMLDecoder(
    customDecoders: customDecoders,
  );

  @override
  Converter<Document, String> get encoder => DocumentHTMLEncoder(
    encodeParsers: encodeParsers,
  );
}

Built-in Parsers

Encoder Parsers

The encoder uses these parsers (from /lib/src/plugins/html/html_document.dart:30-41):
  • HTMLTextNodeParser
  • HTMLBulletedListNodeParser
  • HTMLNumberedListNodeParser
  • HTMLTodoListNodeParser
  • HTMLQuoteNodeParser
  • HTMLHeadingNodeParser
  • HTMLImageNodeParser
  • HtmlTableNodeParser
  • HTMLDividerNodeParser

Color Parsing

Color parsing can be enabled or disabled:
// Enable color parsing (default: true)
DocumentHTMLDecoder.enableColorParse = true;

Creating Custom Parsers

Custom HTML Node Parser (Encoder)

Implement the HTMLNodeParser interface:
class MyCustomHTMLNodeParser extends HTMLNodeParser {
  @override
  String get id => 'my_custom_type';

  @override
  String transformNodeToHTMLString(
    Node node, {
    required List<HTMLNodeParser> encodeParsers,
  }) {
    final text = node.delta?.toPlainText() ?? '';
    return '<div class="custom">$text</div>';
  }
}

Custom Element Parser (Decoder)

Add a custom decoder for specific HTML elements:
Iterable<Node> myCustomElementParser(
  dom.Element element,
  (Delta, Iterable<Node>) Function(
    dom.Element element, {
    String? type,
  }) parseDeltaElement,
) {
  // Parse the element and return nodes
  final (delta, children) = parseDeltaElement(element);
  return [paragraphNode(delta: delta, children: children.toList())];
}

// Use it:
final document = htmlToDocument(
  html,
  customDecoders: {
    'my-element': myCustomElementParser,
  },
);

Advanced Features

Table Support

The HTML plugin fully supports table import and export with:
  • Row and column spanning
  • Nested formatting within cells
  • Table headers (<th>) and data cells (<td>)

Rich Text Formatting

Nested formatting is preserved:
<a href="https://example.com"><strong><em><u>Bold, italic, underlined link</u></em></strong></a>

Google Docs Compatibility

Special handling for documents copied from Google Docs to prevent parsing issues.

Limitations

  • Only network images are supported (URLs starting with http)
  • Some complex CSS properties may not be preserved
  • JavaScript and interactive elements are not supported
  • External stylesheets are not processed

Example: Complete Workflow

import 'package:appflowy_editor/appflowy_editor.dart';

// Import HTML
final html = '''
  <h1>My Document</h1>
  <p>This is a paragraph with <strong>bold</strong> and <em>italic</em> text.</p>
  <ul>
    <li>First item</li>
    <li>Second item</li>
  </ul>
''';

final document = htmlToDocument(html);
final editorState = EditorState(document: document);

// ... user edits document ...

// Export back to HTML
final updatedHtml = documentToHTML(editorState.document);
print(updatedHtml);

See Also

Build docs developers (and LLMs) love