tiny_flutter
A Flutter package that embeds TinyMCE — a browser-based HTML rich text editor — in your app:
- Web —
HtmlElementView+ iframe - macOS, Windows — native WebView (
flutter_inappwebview)
The package ships the editor shell as an asset; your app composes labels, dialogs, and layout around TinyMceEditor.
Disclaimer:
tiny_flutteris an independent community package and is not affiliated with, endorsed by, or maintained by Tiny Technologies (TinyMCE).
Features
✅ Web — Rich text editing via TinyMCE inside Flutter web.
✅ macOS / Windows — Same editor inside a WebView.
❌ Android / iOS — Not supported.
✅ Language — Optional language (en / zh / zh_CN / zh-Hans); defaults to app locale.
✅ Dialog scroll — Forwards mouse wheel to parent scroll views when needed.
✅ Lightweight API — One editor widget plus getEditorContent / setEditorContent.
✅ TinyMCE from CDN — Bundled HTML shell loads TinyMCE from jsDelivr (needs network).
Getting started
Add tiny_flutter to your pubspec.yaml:
dependencies:
tiny_flutter: ^0.0.8
Or from Git:
dependencies:
tiny_flutter:
git:
url: https://github.com/pyaehtookyaw/tiny_flutter.git
Import the library:
import 'package:tiny_flutter/tiny_flutter.dart';
Then complete the host app setup for each platform you ship.
Host app setup
TinyMCE is loaded from the jsDelivr CDN inside a WebView (native) or iframe (web). The host app must allow outbound HTTPS. Do this once in the app that depends on tiny_flutter, not inside this package.
| Platform | Extra setup | Why |
|---|---|---|
| macOS | network.client entitlement |
Sandboxed apps cannot reach the CDN without it |
| Windows | Edge WebView2 Runtime | Native editor uses WebView2 |
| Web | Override flutter_inappwebview_web with this package's stub |
InAppWebView's web plugin fights TinyMCE's iframe |
Native desktop platforms also need a working network the first time the editor opens.
macOS
Sandboxed macOS apps cannot use the network until you allow outbound client connections.
Add this key to both:
macos/Runner/DebugProfile.entitlementsmacos/Runner/Release.entitlements
<key>com.apple.security.network.client</key>
<true/>
Example DebugProfile.entitlements:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.cs.allow-jit</key>
<true/>
<key>com.apple.security.network.server</key>
<true/>
<key>com.apple.security.network.client</key>
<true/>
</dict>
</plist>
Then rebuild:
flutter run -d macos
Windows
- Install Microsoft Edge WebView2 Runtime on the machine that runs the app (Evergreen Bootstrapper is enough for most PCs).
- Rebuild:
flutter run -d windows
Windows 11 usually already has WebView2. On Windows 10, install the runtime if the editor surface is empty.
Web
flutter_inappwebview also ships a web plugin. TinyMCE on Flutter web uses
HtmlElementView, so that plugin must be disabled or the editor can crash on
resize.
If you depend on this package via a path:
dependency_overrides:
flutter_inappwebview_web:
path: ../tiny_flutter/packages/flutter_inappwebview_web_stub
If you depend on Git:
dependency_overrides:
flutter_inappwebview_web:
git:
url: https://github.com/pyaehtookyaw/tiny_flutter.git
path: packages/flutter_inappwebview_web_stub
Then:
flutter run -d chrome
Checklist
macOScom.apple.security.network.clientis in Debug and Release entitlementsWindows has Edge WebView2 RuntimeFlutter web overridesflutter_inappwebview_webwithpackages/flutter_inappwebview_web_stubDevice/machine can reachhttps://cdn.jsdelivr.netAfter changing entitlements or manifests, do a full rebuild (not only hot reload)
Demo

Screenshots (Web)
![]() |
![]() |
|---|---|
| Create article (empty editor) | Update article (demo HTML in editor) |
Example usage
Place TinyMceEditor where you need the editor (often inside a dialog or a Row with your own “Article content” label):
import 'package:flutter/material.dart';
import 'package:tiny_flutter/tiny_flutter.dart';
class ArticleBody extends StatelessWidget {
const ArticleBody({super.key});
@override
Widget build(BuildContext context) {
return Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Flexible(
flex: 1,
child: Row(
children: [
Text('* ', style: TextStyle(color: Colors.red.shade700)),
const Expanded(
child: Text(
'Article content',
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
),
],
),
),
const SizedBox(width: 8),
const Flexible(
flex: 5,
child: TinyMceEditor(
heightFactor: 0.35,
language: 'zh', // or 'en'; omit to use app locale
),
),
],
);
}
}
Future<void> readAndSave() async {
final html = await TinyMceEditor.getEditorContent();
TinyMceEditor.setEditorContent('<p>Hello</p>');
// use html (e.g. send to API)
}
A full flow (home buttons, white dialogs, create vs update) lives in the example app.

