bullet_editor
A structured rich text editor for Flutter built on a single TextField. Supports headings, lists, task items, code blocks, block quotes, inline styles, and full markdown round-trip serialization.
Features
| Block types | Inline styles |
|---|---|
| Paragraph | Bold |
| Heading 1-6 | Italic |
| Bullet list | |
| Numbered list | Inline code |
| Task item (checkbox) | Links |
| Block quote | Autolinks |
| Fenced code block | |
| Divider |
- Markdown shortcuts — type
#,-,1.,>,```,---, etc. - Inline formatting shortcuts — wrap text with
**,*,`,~~ - Keyboard shortcuts — Cmd+B, Cmd+I, Cmd+Shift+S, Tab/Shift+Tab
- Undo/redo with full selection restoration
- Nested blocks via indentation (Tab/Shift+Tab)
- Markdown codec with CommonMark-aligned parsing and round-trip fidelity
- Schema-driven architecture — add custom block types and inline styles
Installation
dependencies:
bullet_editor: ^0.1.0
Or run:
flutter pub add bullet_editor
Quick start
import 'package:bullet_editor/bullet_editor.dart';
import 'package:flutter/material.dart';
class MyEditor extends StatefulWidget {
const MyEditor({super.key});
@override
State<MyEditor> createState() => _MyEditorState();
}
class _MyEditorState extends State<MyEditor> {
late final EditorController<BlockType, InlineStyle> _controller;
@override
void initState() {
super.initState();
_controller = EditorController(
schema: EditorSchema.standard(),
document: Document.empty(BlockType.paragraph),
);
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return BulletEditor(controller: _controller);
}
}
Markdown codec
final schema = EditorSchema.standard();
final codec = MarkdownCodec(schema);
// Decode markdown to a document
final doc = codec.decode('# Hello\n\nA **bold** paragraph.');
// Encode a document back to markdown
final markdown = codec.encode(doc);
Custom schema
final schema = buildStandardSchema(
h1: HeadingStyle(scale: 2.0, fontWeight: FontWeight.w800),
linkColor: Colors.teal,
bulletChar: '–',
);
Add custom block types or inline styles via additionalBlocks and additionalInlineStyles.
Example
See the example app for a full working demo with theme switching and a debug panel.
Architecture
The editor uses a single TextField with a rich TextSpan tree. All block types are rendered inline using WidgetSpan prefixes (bullets, checkboxes, dividers) and styled TextSpan content. This gives native cursor, selection, and IME behavior for free.
The document model is immutable. All mutations go through EditOperation objects applied via Transaction, enabling undo/redo and input rule transforms.
License
MIT — see LICENSE.