Display HTML with Javascript support in FlutterFlow

FlutterFlow provides two built-in components to display HTML, but they can't display local HTML with Javascript:

  • HtmlView only supports HTML and CSS parsing. It does not run Javascript.
  • WebView only supports remote URLs.

In order to display HTML with Javascript support, one has to use a custom Widget. I asked in the Discord, and the prolific skipper113 said I should use a WebViewX.

Basic implementation

I followed the instructions in the FlutterFlow doc to make a custom Widget. There were a few gotchas:

  1. Use "View Boilerplate Code" to generate boilerplate code and avoid basic errors.
  2. Use the Bug icon in the upper right corner. It's hard to see. It will show you what you are missing in your code. In my case, I had to pass width and height to my WebViewX component.

In the end, my component looks like this as a StatefulWidget:

WebView of local HTML with Javascript support

The preview seems to be broken. You have to change the width or html for the first render to happen.

We can safely make it a StatelessWidget:

import 'package:webviewx/webviewx.dart';

class MyHtmlView extends StatelessWidget {
  const MyHtmlView({
    Key? key,
    this.width,
    this.height,
    this.html
  }) : super(key: key);

  final double? width;
  final double? height;
  final String? html;

  @override
  Widget build(BuildContext context) {
    return WebViewX(
      width: width!,
      height: height!,
      initialContent: html ?? '',
      initialSourceType: SourceType.html
    );
  }
}

As a StatelessWidget, preview seems to not work at all, and just show a blank preview. But if I run it, it runs fine.

Fixing the scrolling issue

However, I ended up with an issue where any scroll gesture within the WebViewX would scroll its content, but block its parent Container from scrolling. It results in a frustrating browsing experience. In the docs for WebViewX, they do mention this issue and recommend to wrap the container of the WebViewX (a Column in my case) in a WebViewAware Widget. That means I need to wrap my Column in a WebViewAware. However, WebViewAware is not a standard FlutterFlow component. It is a Widget defined by the webviewx package. And as far as I can tell, I can't make a custom container Widget: the dropdown of type of parameters does not include Widget:

The parameter type dropdown does not include Widget.

Even if I try writing a proper container component:

import 'package:webviewx/webviewx.dart';

class ContentAware extends StatelessWidget {
  const ContentAware({
    Key? key,
    this.width,
    this.height,
    this.child
  }) : super(key: key);

  final double? width;
  final double? height;
  final Widget? child;

  @override
  Widget build(BuildContext context) {
    return WebViewAware(child: child!);
  }
}

The IDE does not treat it as a container in the end.

My custom container Widget is not treated as a proper Container. Notice there is no + button on the right of the component.

WebViewX has a ignoreAllGestures property. If I set it to true, then everything scrolls well, but I can't even click the content anymore: I can't click any link or start any video content.

So my workaround for now, is to simply wrap the WebViewX with a Card, and give it a background color, to clearly show to the user that scrolling should be done outside the card.