-
-
Notifications
You must be signed in to change notification settings - Fork 889
Migration Guides
3.0.0 modularizes the library to remove unnecessary dependencies that you may not need in your app, allowing support for all Flutter-supported platforms, and a lightweight base library that meets a lot of use cases, with the option of adding more features through 1st-party packages.
If you have any further questions after reading through this guide, feel free to make an Issue or Discussion Q&A post.
customRender
has been changed to extensions
, and its API is now significantly different.
extensions
accepts a List<Extension>
.
Migration
- If your current custom render returns a widget:
"flutter": (RenderContext context, Widget child) {
return FlutterLogo(
style: (context.tree.element!.attributes['horizontal'] != null)
? FlutterLogoStyle.horizontal
: FlutterLogoStyle.markOnly,
textColor: context.style.color!,
size: context.style.fontSize!.size! * 5,
);
},
becomes
TagExtension(
tagsToExtend: {"flutter"},
builder: (extensionContext) {
return FlutterLogo(
style: extensionContext.attributes['horizontal'] != null
? FlutterLogoStyle.horizontal
: FlutterLogoStyle.markOnly,
textColor: extensionContext.styledElement!.style.color!,
size: extensionContext.styledElement!.style.fontSize!.value,
);
},
),
- If your current custom render returns an
InlineSpan
:
"bird": (RenderContext context, Widget child) {
return TextSpan(text: "🐦");
},
becomes
TagExtension.inline(tagsToExtend: {"bird"}, child: TextSpan(text: "🐦")),
If you were previously using the child
parameter, you'll need to override the Extension
class and create your own custom extension.
For more details, see How To Use Extensions
This parameter is removed and needs to be migrated to use an ImageExtension
.
Migration
The old way:
ImageSourceMatcher customUriMatcher() => (attributes, element) =>
attributes['src'] != null && attributes['src']!.startsWith("custom:");
ImageRender customImageRender() => (context, attributes, element) {
return CustomImage.network(
attributes["src"]!.replace("custom:", ""),
width: double.tryParse(attributes["width"]),
height: double.tryParse(attributes["height"]),
);
};
...
Html(
customImageRenders: {
customUriMatcher(): customImageRender(),
}
),
becomes
Html(
extensions: [
ImageExtension(
matchesAssetImages: false,
matchesDataImages: false,
networkSchemas: {"custom:"},
builder: (extensionContext) {
final element = extensionContext.styledElement as ImageElement;
return CustomImage.network(
element.src.replace("custom:", ""),
width: element.width,
height: element.height,
);
}
),
],
),
This parameter is removed. Add the flutter_html_iframe package, and then add this extension to the Html
widget:
extensions: [
IframeHtmlExtension(
navigationDelegate: (request) {
//Return decision here
},
),
],
This parameter is removed. Default behavior is just to show alt text when an image encounters an error. Please create a custom Extension
if you need to do additional image error handling.
This parameter is removed. Instead, add the OnImageTapExtension
:
Html(
data: ...,
extensions: [
OnImageTapExtension(
onImageTap: (src, imgAttributes, element) {
// Handle an image being tapped
},
),
],
)
RenderContext
has been removed from the onLinkTap
callback.
This parameter is removed. Add the flutter_html_math package, and then add this extension to the Html
widget:
extensions: [
MathHtmlExtension(
onMathErrorBuilder: //Your error builder here
),
],
This parameter has been split into two different options: doNotRenderTheseTags
and onlyRenderTheseTags
. All supported tags are allowed by default, including tags supported by extensions. This allows you to either restrict certain tags from rendering (say you don't want any images rendered), or allow only a certain subset of tags to render (say you only want h1
-h6
and p
tags to be rendered).
Both doNotRenderTheseTags
and onlyRenderTheseTags
take a Set<String>
.
You can only apply one of these options to your Html widget. Including both will trigger an assertion.
If you were using the style
parameter in your Html
widget, there are some minor changes to the API that introduce some huge possibilites:
Version 3.0.0 introduces support for length/percent/auto units for several properties on Style
.
As a basic example:
Style(
width: 100,
)
becomes
Style(
width: Width(100, Unit.px),
// Including Unit.px is optional. `Unit`s generally default to px if only one argument is used in the constructor.
)
Or, if you are feeling fancy, all of the below are currently supported:
Width(1.5, Unit.em),
Width(50, Unit.percent),
Width.auto(), //Which is a shortcut for Width(0, Unit.auto), and is the default for the width parameter.
The following Style
properties now have support for the Unit
:
width
, height
, fontSize
, margin
, lineHeight
2.0.0
2.0.0 introduced support for Flutter Web and migrated the library to use null safety. There were few breaking changes. See the CHANGELOG for more information
1.0.0
1.0.0 is a major release with tons of new features to be excited about!
Unfortunately, to bring you these new features, there had to be a lot of breaking changes and deprecation of parameters. If you're trying to migrate your old Html
widget code to 1.0.0, this is the page for you.
We completely rewrote the old parser to use a combination of RichText
and Widget
s so that your Html looks even more natural in your app.
useRichText
now defaults to false
, since the new parser has so many new features and fewer bugs than the RichTextParser. The RichTextParser
has been deprecated and will be removed sometime in the next couple versions (no later than version 1.3.0).
NOTE: THIS IS THE EASY WAY OUT (i.e. you need to push a quick fix on a Friday afternoon and don't want to deal with migrating this plugin to 1.0.0)
If you would like your HTML to remain unchanged and you previously did not have useRichText
set to false
, then set useRichText
to true to continue using the RichText
parser as you were. Note that you will receive none of the benefits of 1.0.0 if you do this, so you might be better off setting your flutter_html
version to 0.11.0
.
Take a look at the deprecated/changed/new parameters below, and follow the migration guide for any that you are currently using. Open an issue if you encounter any difficulties in the migration to 1.0.0. We're hoping these changes make your code much cleaner and more intuitive to you and anyone else who has to deal with your code.
data
remains the same in 1.0.0 as it was before. Just pass in your HTML code and the Widget will parse it:
Html(
data: "<h1>Hello, World!</h1>",
),
NOTE: NOT YET AVAILABLE
The css
parameter is new in 1.0.0. Similar to data
, but for your CSS code. Great for if you have an external css file you'd like to apply to your HTML.
Html(
data: "<h1 class='example'>Example</h1>",
css: ".example { font-family: serif; background-color: blue; }",
),
customRender
is completely different in 1.0.0. You can also read more about customRender
on its wiki page.
Html(
data: ...,
customRender: (dom.Node node, children) {
if(node is dom.Element) {
if(node.localName == "flutter") {
return FlutterLogo();
}
}
},
),
Html(
data: ...,
customRender: {
"flutter": (RenderContext context, child, attributes) {
// This example is simple and doesn't use any of the provided parameters.
// See the linked wiki page for more examples.
return FlutterLogo();
}
},
),
The padding
parameter seems a bit silly when you can wrap the entire Html widget in a Padding
widget.
Or if you still want the Html content itself to be padded, then you make the following migration:
Html(
data: ...,
padding: 24,
),
Html(
data: ...,
style: {
"html": Style(
padding: const EdgeInsets.all(24),
),
},
),
The new style
property makes the backgroundColor
property redundant.
Here's the migration you should make:
Html(
data: ...,
backgroundColor: Colors.yellow,
),
Html(
data: ...,
style: {
"html": Style(
backgroundColor: Colors.yellow,
),
},
),
If you were using defaultTextStyle
to make the Html
widget take the text style of the current theme, then you can just remove the defaultTextStyle
parameter from your code. The Html
widget will now automatically pull the default text style from Theme.of(context).textTheme.body1
.
If you'd like your Html
widget to have a different default text style, you can make the following migration:
Html(
data: ...,
defaultTextStyle: myCustomTextStyle,
),
Html(
data: ...,
style: {
"html": Style.fromTextStyle(myCustomTextStyle),
},
),
The onLinkTap
parameter is pretty much unchanged in version 1.0.0. However, internally, the onLinkTap
callback type has been renamed from OnLinkTap
to OnTap
. It still has the same signature, so this shouldn't affect most people.
Html(
data: ...,
onLinkTap: (String url) {
//Do something (e.g. launch(url)).
}
),
The new style
attribute supports preserving newlines in the original code. The migration is fairly simple.
Html(
data: ...,
renderNewlines: true,
),
Html(
data: ...,
style: {
"html": Style(whiteSpace: WhiteSpace.PRE),
},
),
In the new parser, it's now so much easier to apply custom margins/padding to html elements. Just use the new style
attribute as shown in the following example migration:
Html(
data: ...,
customEdgeInsets: (dom.Node node) {
if(node is dom.Element) {
if(node.localName == "h1" || node.localName == "h4") {
return EdgeInsets.all(48);
}
}
},
),
Html(
data: ...,
style: {
"h1, h4": Style(
margin: EdgeInsets.all(48),
),
},
),
It's now much easier to apply custom text styles to any element using the style
parameter.
Html(
data: ...,
customTextStyle: (dom.Node node, TextStyle baseStyle) {
if(node is dom.Element) {
if(node.localName == "span" || node.localName == "h4") {
return baseStyle.merge(TextStyle(fontFamily: 'serif'));
}
}
return baseStyle;
},
),
Html(
data: ...,
style: {
"span, h4": Style(
fontFamily: 'serif',
),
//Alternatively, apply a style from an existing TextStyle:
"span, h4": Style.fromTextStyle(
TextStyle(fontFamily: 'serif'),
),
},
),
The new parser doesn't use a global block spacing. Now, just apply margin to the desired elements.
The following migration would be common:
Html(
data: ...,
blockSpacing: 24,
),
Html(
data: ...,
style: {
"h1, div": Style(
margin: EdgeInsets.symmetric(vertical: 24),
),
},
),
The new parser is built off of the core concepts of the RichText
parser, and brings the best of the RichText
parser along with it, so you shouldn't ever need to set this parameter.
As a side note, useRichText
now defaults to false
and must explicitly be set to true.
NOTE: NOT YET AVAILABLE
Aligning text is fairly straightforward with the new style
parameter.
Html(
data: ...,
customTextAlign: (dom.Element elem) {
if(elem.localName == "p") {
return TextAlign.center;
}
return TextAlign.left
},
),
Html(
data: ...,
style: {
//Not yet available
},
),
This parameter is unchanged.
Html(
data: ...,
onImageError: (dynamic exception, StackTrace stackTrace) {
//Do something when an image fails to load.
},
),
Just use the new style
parameter to do any custom link styling.
Html(
data: ...,
linkStyle: TextStyle(
textDecoration: TextDecoration.underline,
color: Colors.red,
),
),
Html(
data: ...,
style: {
"a": Style(
// Note that the underline can be omitted, since the new parser merges styles with the element's
// default style rather than replacing that style.
color: Colors.red,
),
},
),
Due to the way the new parser renders stuff, there may be some slight changes to the way shrink-wrapped content was rendered. For most cases, though, the result should be nearly identical to the way it was in the RichText
parser.
In the past, the <body>
tag was always added even if it wasn't explicitly included. Due to the new style
features, the <body>
tag is given a margin by default like a browser would do, so you may have to explicitly remove the margin as outlined in the migration below:
Html(
data: ...,
shrinkWrap: true,
),
Html(
data: ...,
shrinkWrap: true,
// The <body> tag in the new parser has a default margin, so you (optionally)
// need to remove it to get the same result as before.
style: {
"body": Style(margin: EdgeInsets.zero),
}
),
All the different properties available in the imageProperties
options are available to you either through the customRender
parameter or the style
parameter.
Migration guide coming soon.
There have been no changes to the onImageTap
callback.
Html(
data: ...,
onImageTap: (url) {
//Do something with image.
}
),
We've added the more generalized parameter blacklistedElements
for handling which elements are rendered or not.
Html(
data: ...,
showImages: false,
),
Html(
data: ...,
blacklistedElements: ["img"],
),
This parameter is good for controlling which elements are displayed or hidden. For instance, if you didn't want <iframe>
or <video>
elements to be rendered, then the following could be written:
Html(
data: ...,
blacklistedElements: ["iframe", "video"],
),
Most of the migrations above involved this new style
parameter. The style
parameter is essentially a Dart object representation of a simplified subset of CSS. Styles cascade in the same way that CSS does, and this gives you fine-tuned control over every pixel of the way your HTML renders its widgets.
The style
attribute takes a Map<String, Style>
that maps CSS selectors to Style
s.
For more info, see the style wiki page.
Html(
data: ...,
style: {
"body": Style(
backgroundColor: Colors.black,
color: Colors.white,
),
"div": Style(
border: Border(bottom: BorderSide(color: Colors.grey)),
width: 200,
fontFamily: 'serif',
),
"a": Style(
textDecoration: TextDecoration.none,
backgroundColor: Colors.deepPurple,
),
},
),