๐ผ๏ธ Flutter Web Image Upload Using dart:html
and HTTP Request
๐ Introduction
Uploading images in a Flutter Web application can be slightly different from mobile due to platform limitations. On the web, you don’t have access to the typical file pickers from mobile SDKs. Instead, you must rely on dart:html
to interact with the browser and handle file selection.
In this tutorial, weโll build a simple Flutter Web app that allows the user to:
-
Select an image file from their device
-
Preview the image
-
Upload it to a remote server using a PHP API
Letโs dive into the code and walk through each part!
๐ ๏ธ Setting Up the Project
Start with a basic Flutter Web app. If you havenโt already, enable web support:
Replace the contents of lib/main.dart
with the code below.
๐ Full Code
import 'dart:html' as html; import 'dart:typed_data'; import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; void main() { runApp(MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Image Upload', theme: ThemeData( primarySwatch: Colors.blue, ), home: ImageUploadPage(), ); } } class ImageUploadPage extends StatefulWidget { @override _ImageUploadPageState createState() => _ImageUploadPageState(); } class _ImageUploadPageState extends State<ImageUploadPage> { Uint8List? _imageData; // Select image from device void _pickImage() async { final input = html.FileUploadInputElement()..accept = 'image/*'; input.click(); input.onChange.listen((e) async { final files = input.files; if (files!.isEmpty) return; final reader = html.FileReader(); reader.readAsArrayBuffer(files[0]!); reader.onLoadEnd.listen((e) { setState(() { _imageData = reader.result as Uint8List; }); }); }); } // Upload selected image to the server Future<void> _uploadImage() async { if (_imageData == null) { print('No image data to upload'); return; } final request = http.MultipartRequest( 'POST', Uri.parse('https://acesoftech.co.in/API/image_upload/image_upload.php'), ); request.files.add(http.MultipartFile.fromBytes( 'image', _imageData!, filename: 'image.jpg', )); try { final response = await request.send(); if (response.statusCode == 200) { print('Image uploaded successfully'); } else { print('Upload failed with status code ${response.statusCode}'); } } catch (e) { print('An error occurred: $e'); } } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text('Image Upload')), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ _imageData == null ? Text('No image selected.') : Image.memory(_imageData!), SizedBox(height: 20), ElevatedButton( onPressed: _pickImage, child: Text('Pick Image'), ), SizedBox(height: 20), ElevatedButton( onPressed: _uploadImage, child: Text('Upload Image'), ), ], ), ), ); } }
๐งฉ Explanation
๐ Picking the Image
We use dart:html
‘s FileUploadInputElement
to open the native browser file picker:
Once the user selects an image, we read it using FileReader
as a byte array (Uint8List
) and store it in _imageData
.
๐ค Uploading the Image
We use http.MultipartRequest
to upload the image as a multipart form:
โ ๏ธ Ensure your backend API (PHP in this case) is set up to handle multipart file uploads. The key
'image'
should match the$_FILES['image']
field on your server.
๐ผ๏ธ Displaying the Image
If _imageData
is available, we use Image.memory()
to display a preview:
If you test this inย IOS. it will throw error of html . so here is the modified code for IOS compatible also
import 'dart:typed_data'; import 'dart:io' as io; import 'package:flutter/foundation.dart'; // for kIsWeb import 'package:flutter/material.dart'; import 'package:image_picker/image_picker.dart'; import 'package:http/http.dart' as http; void main() { runApp(MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Image Upload', theme: ThemeData(primarySwatch: Colors.blue), home: ImageUploadPage(), ); } } class ImageUploadPage extends StatefulWidget { @override _ImageUploadPageState createState() => _ImageUploadPageState(); } class _ImageUploadPageState extends State<ImageUploadPage> { Uint8List? _imageData; XFile? _pickedFile; final ImagePicker _picker = ImagePicker(); Future<void> _pickImage() async { final XFile? image = await _picker.pickImage(source: ImageSource.gallery); if (image == null) return; setState(() { _pickedFile = image; }); if (kIsWeb) { // For web, we need to read bytes final bytes = await image.readAsBytes(); setState(() { _imageData = bytes; }); } else { // For mobile, we can just display using the file final bytes = await image.readAsBytes(); setState(() { _imageData = bytes; }); } } Future<void> _uploadImage() async { if (_pickedFile == null) { print('No image selected'); return; } final uri = Uri.parse('https://acesoftech.co.in/API/image_upload/image_upload.php'); var request = http.MultipartRequest('POST', uri); if (kIsWeb) { request.files.add( http.MultipartFile.fromBytes( 'image', _imageData!, filename: _pickedFile!.name, ), ); } else { request.files.add( await http.MultipartFile.fromPath( 'image', _pickedFile!.path, ), ); } try { final response = await request.send(); if (response.statusCode == 200) { print('Image uploaded successfully!'); } else { print('Upload failed with status: ${response.statusCode}'); } } catch (e) { print('Error uploading image: $e'); } } @override Widget build(BuildContext context) { Widget imageWidget = _imageData == null ? Text('No image selected.') : Image.memory(_imageData!, height: 200); return Scaffold( appBar: AppBar(title: Text('Image Upload')), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ imageWidget, SizedBox(height: 20), ElevatedButton( onPressed: _pickImage, child: Text('Pick Image'), ), SizedBox(height: 20), ElevatedButton( onPressed: _uploadImage, child: Text('Upload Image'), ), ], ), ), ); } }
โ Summary
In this tutorial, we learned how to:
-
Use
dart:html
for file input in a Flutter Web project -
Convert selected image data into bytes
-
Display a preview of the image using
Image.memory
-
Upload the image to a server using
http.MultipartRequest
This approach works great for basic web uploads and can be expanded to include drag-and-drop support, file size/type validation, upload progress bars, etc.