Skip to main content
Text block components are the foundation of content in AppFlowy Editor. They handle rich text rendering, editing, and formatting for blocks like paragraphs, headings, lists, and quotes.

Overview

Text block components include:
  • ParagraphBlockComponent - Standard text paragraphs
  • HeadingBlockComponent - Headings (H1-H6)
  • BulletedListBlockComponent - Bulleted list items
  • NumberedListBlockComponent - Numbered list items
  • TodoListBlockComponent - Todo list items with checkboxes
  • QuoteBlockComponent - Quote blocks
All text blocks use the AppFlowyRichText widget for rendering.

Common structure

Text block components typically follow this structure:
class TextBlockComponentWidget extends BlockComponentStatefulWidget {
  const TextBlockComponentWidget({
    super.key,
    required super.node,
    required super.configuration,
    super.showActions,
    super.actionBuilder,
    required this.editorState,
  });

  final EditorState editorState;

  @override
  State<TextBlockComponentWidget> createState() => _TextBlockComponentWidgetState();
}

ParagraphBlockComponent

The most basic text block component.

ParagraphBlockComponentBuilder

class ParagraphBlockComponentBuilder extends BlockComponentBuilder {
  ParagraphBlockComponentBuilder({
    super.configuration,
  });

  @override
  BlockComponentWidget build(BlockComponentContext blockComponentContext) {
    return ParagraphBlockComponentWidget(
      key: blockComponentContext.node.key,
      node: blockComponentContext.node,
      configuration: configuration,
      showActions: showActions(blockComponentContext.node),
      actionBuilder: (context, state) => actionBuilder(blockComponentContext, state),
      editorState: blockComponentContext.buildContext.read<EditorState>(),
    );
  }
}

Creating paragraph nodes

final paragraphNode = paragraphNode(
  text: 'Hello, world!',
  attributes: {
    'delta': [
      {'insert': 'Hello, world!'},
    ],
  },
);

HeadingBlockComponent

Renders headings with different levels (1-6).

HeadingBlockComponentBuilder

class HeadingBlockComponentBuilder extends BlockComponentBuilder {
  HeadingBlockComponentBuilder({
    super.configuration,
  });

  @override
  BlockComponentWidget build(BlockComponentContext blockComponentContext) {
    return HeadingBlockComponentWidget(
      key: blockComponentContext.node.key,
      node: blockComponentContext.node,
      configuration: configuration,
      showActions: showActions(blockComponentContext.node),
      actionBuilder: (context, state) => actionBuilder(blockComponentContext, state),
      editorState: blockComponentContext.buildContext.read<EditorState>(),
    );
  }
}

Creating heading nodes

final headingNode = headingNode(
  level: 1,
  text: 'My Heading',
);

Heading attributes

level
int
required
Heading level (1-6). Controls the font size and weight.
delta
List<Map<String, dynamic>>
required
Text content and formatting in Delta format.

List block components

List blocks support nesting and custom icons.

BulletedListBlockComponentBuilder

class BulletedListBlockComponentBuilder extends BlockComponentBuilder {
  BulletedListBlockComponentBuilder({
    super.configuration,
    this.iconBuilder,
  });

  final BlockIconBuilder? iconBuilder;

  @override
  BlockComponentWidget build(BlockComponentContext blockComponentContext) {
    return BulletedListBlockComponentWidget(
      key: blockComponentContext.node.key,
      node: blockComponentContext.node,
      configuration: configuration,
      iconBuilder: iconBuilder,
      showActions: showActions(blockComponentContext.node),
      actionBuilder: (context, state) => actionBuilder(blockComponentContext, state),
      editorState: blockComponentContext.buildContext.read<EditorState>(),
    );
  }
}

Custom list icons

final bulletBuilder = BulletedListBlockComponentBuilder(
  configuration: configuration,
  iconBuilder: (context, node) {
    return const Icon(
      Icons.circle,
      size: 8,
      color: Colors.blue,
    );
  },
);

NumberedListBlockComponentBuilder

Similar to bulleted lists but with numbers:
class NumberedListBlockComponentBuilder extends BlockComponentBuilder {
  NumberedListBlockComponentBuilder({
    super.configuration,
    this.iconBuilder,
  });

  final BlockIconBuilder? iconBuilder;
}

TodoListBlockComponent

Todo lists have a checkbox and checked state.

TodoListBlockComponentBuilder

class TodoListBlockComponentBuilder extends BlockComponentBuilder {
  TodoListBlockComponentBuilder({
    super.configuration,
    this.iconBuilder,
  });

  final BlockIconBuilder? iconBuilder;
}

Todo list attributes

checked
bool
required
Whether the todo item is checked.
delta
List<Map<String, dynamic>>
required
Text content in Delta format.

Custom todo icons

final todoBuilder = TodoListBlockComponentBuilder(
  configuration: configuration,
  iconBuilder: (context, node) {
    final checked = node.attributes[TodoListBlockKeys.checked] as bool;
    return Icon(
      checked ? Icons.check_box : Icons.check_box_outline_blank,
      size: 20,
      color: checked ? Colors.blue : Colors.grey,
    );
  },
);

QuoteBlockComponent

Quote blocks with optional icon indicator.

QuoteBlockComponentBuilder

class QuoteBlockComponentBuilder extends BlockComponentBuilder {
  QuoteBlockComponentBuilder({
    super.configuration,
    this.iconBuilder,
  });

  final BlockIconBuilder? iconBuilder;
}

Custom quote icons

final quoteBuilder = QuoteBlockComponentBuilder(
  configuration: configuration,
  iconBuilder: (context, node) {
    return const EditorSvg(
      width: 20,
      height: 20,
      name: 'quote',
      color: Colors.grey,
    );
  },
);

BlockIconBuilder

Many text block components support custom icon builders:
typedef BlockIconBuilder = Widget Function(
  BuildContext context,
  Node node,
);
Example:
BlockIconBuilder myIconBuilder = (context, node) {
  return Icon(
    Icons.star,
    size: 20,
    color: Theme.of(context).primaryColor,
  );
};

Common methods

Building text content

All text blocks use AppFlowyRichText internally:
AppFlowyRichText(
  node: node,
  editorState: editorState,
  textSpanDecorator: textSpanDecorator,
  placeholderText: placeholderText,
  textDirection: textDirection,
  cursorColor: cursorColor,
  selectionColor: selectionColor,
)

Handling user input

Text blocks handle input through the editor state:
editorState.insertTextAtCurrentSelection(text);
editorState.formatTextWithEmbedded(attributes);
editorState.deleteTextInSelection();

Helper functions

Convenience functions for creating text nodes:

paragraphNode()

Node paragraphNode({
  String? text,
  Delta? delta,
  Attributes? attributes,
  Iterable<Node>? children,
})

headingNode()

Node headingNode({
  required int level,
  String? text,
  Delta? delta,
  Attributes? attributes,
})

bulletedListNode()

Node bulletedListNode({
  String? text,
  Delta? delta,
  Attributes? attributes,
  Iterable<Node>? children,
})

numberedListNode()

Node numberedListNode({
  String? text,
  Delta? delta,
  Attributes? attributes,
  Iterable<Node>? children,
})

todoListNode()

Node todoListNode({
  required bool checked,
  String? text,
  Delta? delta,
  Attributes? attributes,
  Iterable<Node>? children,
})

quoteNode()

Node quoteNode({
  String? text,
  Delta? delta,
  Attributes? attributes,
})

AppFlowyRichText

Rich text rendering API

Block Components

Guide to block components

Build docs developers (and LLMs) love