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:
- Use "View Boilerplate Code" to generate boilerplate code and avoid basic errors.
- 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:
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:
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.
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.