quill_delta_html
Lossless bidirectional Quill Delta ↔ HTML conversion.
- Round-trip lossless:
decode(encode(delta)) == deltafor every Delta the encoder produces. 450+ tests including fuzz seeds and whitespace-torture cases (NBSP, ZWSP, ZWNJ, ZWJ, EN/EM/THIN/IDEOGRAPHIC SPACE, tab, CR, surrogate-pair emoji). - Streaming: encoder writes through
HtmlWriterstraight into a StringBuffer — no intermediate DOM tree. - Embed adapters: image, video, audio, divider, formula, mention, table, iframe (sandbox-aware), oembed, passthrough. URL sniffs for YouTube, Vimeo, Loom, Spotify, SoundCloud, CodePen, Twitter.
- Sync entry points:
HtmlImporter.importSync/HtmlExporter.exportSync.
Quickstart
import 'package:dart_quill_delta/dart_quill_delta.dart';
import 'package:quill_delta_html/quill_delta_html.dart';
final codec = QuillHtmlCodec();
// Delta -> HTML.
final delta = Delta()..insert('Hello, world.\n');
final html = codec.encode(delta);
// HTML -> Delta.
final back = codec.decode(html);
With explicit options
final codec = QuillHtmlCodec(
options: const HtmlOptions(
wrapDocument: false,
preserveWhitespace: true,
canonicalColorFormat: ColorFormat.hex6,
),
);
Custom embed adapter
class GistAdapter extends EmbedAdapter {
@override String get type => 'gist';
@override
void encode({
required HtmlWriter writer,
required Object? value,
Map<String, dynamic>? siblingAttrs,
required QuillHtmlOptions options,
}) {
final url = value?.toString() ?? '';
writer.open('script', {'src': '$url.js'});
writer.close('script');
}
@override
bool matches(dom.Element el) =>
el.localName == 'script' &&
(el.attributes['src'] ?? '').endsWith('.js') &&
(el.attributes['src'] ?? '').contains('gist.github.com');
@override
Map<String, dynamic>? decode(dom.Element el, QuillHtmlOptions options) {
final src = el.attributes['src'];
return src == null
? null
: {'insert': {'gist': src.replaceAll('.js', '')}};
}
}
final codec = QuillHtmlCodec(
registry: EmbedRegistry(user: [GistAdapter()]),
);
Iframe sanitization
QuillHtmlCodec(
options: QuillHtmlOptions(
iframePolicy: IframePolicy(
allowedSchemes: const {'https'},
allowedHosts: const {'www.youtube.com', 'player.vimeo.com'},
requireSandbox: true,
),
),
);
Libraries
- quill_delta_html
- Lossless bidirectional Quill Delta <-> HTML conversion.