How To Download Files With The web Package In Flutter Apps
Introduction Link to heading
Since the release of Dart 3.7, your Flutter web app will give you warnings when you use dart:html in your code and have the latest Dart version activated. It was deprecated by the Flutter team. In this article, I am going to show you how to download files with the web package in Flutter apps. To do that, we will remove dart:html, replace it with the web package, and apply some code changes.
Here is more information about what was deprecated and here is a migration guide about refactoring dart:html.

Breaking changes and deprecations Link to heading
A list of breaking changes by release in Dart.

Migrate to package:web Link to heading
How to migrate web interop code from dart:html to package:web.
The use case Link to heading
You have a Flutter web app and want to give your users the ability to download text files like CSV that are created on the fly.
Let’s assume, your app tracks the daily steps of a user. They can download monthly summaries with steps per day. This is a good example for a CSV file and can be easily used by other apps like Google Docs or Microsoft Office.
Here is how to download files with the web package in Flutter apps and fix the warnings from the Dart analyzer.
The old way Link to heading
You probably have a dart:html import like this in your code.
Dartimport ‘dart:convert’; // ignore: avoid_web_libraries_in_flutter import ‘dart:html’ as html;
import 'dart:convert';
// ignore: avoid_web_libraries_in_flutter
import 'dart:html' as html;
And you also have a download function to trigger a browser download like the one below. We assume here that csv already contains the prepared content.
DartFuture _download(String csv, String fileName) async { final bytes = utf8.encode(csv); final blob = html.Blob([bytes]); final url = html.Url.createObjectUrlFromBlob(blob); final anchor = html.document.createElement(‘a’) as html.AnchorElement ..href = url ..style.display = ’none’ ..download = ‘$fileName.csv’; html.document.body!.children.add(anchor); anchor.click(); html.document.body!.children.remove(anchor); html.Url.revokeObjectUrl(url); }
Future _download(String csv, String fileName) async {
final bytes = utf8.encode(csv);
final blob = html.Blob([bytes]);
final url = html.Url.createObjectUrlFromBlob(blob);
final anchor = html.document.createElement('a') as html.AnchorElement
..href = url
..style.display = 'none'
..download = '$fileName.csv';
html.document.body!.children.add(anchor);
anchor.click();
html.document.body!.children.remove(anchor);
html.Url.revokeObjectUrl(url);
}
This is what most AIs will propose to you at the moment when you ask them how such a download can be achieved. It still works but any future version could drop support for this piece of code.
The new way Link to heading
Instead of dart:html, the new way is to use the web package. The obvious first step is to install it with this command:
Bashflutter pub add web
flutter pub add web
Then, we focus on the _download() function. Here is the updated version:
DartFuture _download(String csv, String fileName) async { final blobParts = ([csv] as dynamic) as JSArray; final blob = Blob(blobParts, BlobPropertyBag(type: ’text/csv’)); final url = URL.createObjectURL(blob); final anchor = HTMLAnchorElement() ..href = url ..download = ‘$fileName.csv’; document.body?.append(anchor); anchor.click(); anchor.remove(); URL.revokeObjectURL(url); }
Future _download(String csv, String fileName) async {
final blobParts = ([csv] as dynamic) as JSArray<BlobPart>;
final blob = Blob(blobParts, BlobPropertyBag(type: 'text/csv'));
final url = URL.createObjectURL(blob);
final anchor =
HTMLAnchorElement()
..href = url
..download = '$fileName.csv';
document.body?.append(anchor);
anchor.click();
anchor.remove();
URL.revokeObjectURL(url);
}
We replaced all references to the old dart:html package. The call toJS is a little tricky and it took me a while to figure it out until the compiler stopped complaining.
To round things up, we update the import section as follows:
Dartimport ‘dart:js_interop’; import ‘package:web/web.dart’;
import 'dart:js_interop';
import 'package:web/web.dart';
With that, your function should work again and not produce any more deprecation warnings!
Conclusion Link to heading
With Dart 3.7, you need to make some changes to your code and move away from dart:html. In this article I showed you how to do that on a common example. Removing deprecated code parts is always recommended to make your code ready for the future.
Related articles Link to heading

How To Fix Firebase Hosting Errors When Using Automatic Deployment With GitHub Link to heading
Fix a pipeline error with status code 403 and the message “Resource not accessible by integration”

How to fix a broken branch after a git merge or git rebase Link to heading
This guide shows you how you can create a new branch with the original changes of your broken branch.

How To Fix API Calls That Always Return 401 With Access Token Link to heading
I stumbled across a problem when accessing the Gumroad API that always returns 401 with an access token. Here is a solution for you!