tiny_flutter

A Flutter package that embeds TinyMCE — a browser-based HTML rich text editor — in your app:

  • WebHtmlElementView + 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_flutter is 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.entitlements
  • macos/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

  1. Install Microsoft Edge WebView2 Runtime on the machine that runs the app (Evergreen Bootstrapper is enough for most PCs).
  2. 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

  • macOS com.apple.security.network.client is in Debug and Release entitlements
  • Windows has Edge WebView2 Runtime
  • Flutter web overrides flutter_inappwebview_web with packages/flutter_inappwebview_web_stub
  • Device/machine can reach https://cdn.jsdelivr.net
  • After changing entitlements or manifests, do a full rebuild (not only hot reload)

Demo

Tiny Flutter — Flutter web example

Screenshots (Web)

Create article dialog Update article dialog
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.

Libraries

tiny_flutter