๐ Build Your Portfolio Website Using Flutter Web and Dio
In todayโs world, having a strong digital presence is essentialโespecially if youโre a developer or freelancer. One of the best ways to showcase your skills is through a personal portfolio website. And now, with Flutter Web, you can create beautiful, cross-platform portfolio websites using just one codebase.
In this guide, youโll learn how to build a modern, mobile-friendly portfolio site using Flutter Web, enhanced with Dio to handle contact form submissions.
๐ฆ What is Dio?
Dio is a powerful HTTP client for Dart, widely used in Flutter apps. It offers features like interceptors, global configuration, form handling, and more. In this project, weโll use it to submit contact forms directly to an API.
Install Dio:
dependencies:
dio: ^5.4.0
๐ ๏ธ Project Overview
The portfolio will contain the following sections:
- About Me
- My Skills
- My Portfolio
- Contact Us
๐ก Set Up the Project
flutter create portfolio_web
cd portfolio_web
flutter run -d chrome
๐ผ๏ธ Create the Screens
Create separate Dart files in your screens/ folder for each section.
1. About Me
class AboutMe extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Center(
child: Text(\"Hi, I'm a Flutter Developer passionate about clean UI.\"),
);
}
}
2. My Skills
final skills = ['Flutter', 'Dart', 'Firebase', 'Dio'];
ListView.builder(
itemCount: skills.length,
itemBuilder: (context, index) => ListTile(
leading: Icon(Icons.check),
title: Text(skills[index]),
),
);
3. Portfolio
final projects = [
{'title': 'To-Do App', 'description': 'A task manager with cloud sync'},
];
ListView.builder(
itemCount: projects.length,
itemBuilder: (context, index) => ListTile(
title: Text(projects[index]['title']!),
subtitle: Text(projects[index]['description']!),
),
);
4. Contact Us (with Dio)
final dio = Dio();
final nameController = TextEditingController();
ElevatedButton(
onPressed: () async {
await dio.post('https://your-api.com/contact', data: {
'name': nameController.text,
'email': emailController.text,
'message': messageController.text,
});
},
child: Text('Submit'),
);
๐ Deploy Your Website
flutter build web
This command generates the website in the /build/web folder. You can host it using:
- GitHub Pages
- Firebase Hosting
- Netlify / Vercel
๐ How to Use Dio Interceptors in Your Flutter Web Portfolio
Dio is one of the most powerful HTTP clients for Flutter. But did you know you can add an Interceptor to log, modify, or handle API requests globally? ๐ In this quick guide, youโll learn how to use InterceptorsWrapper with Dio in your Flutter Web portfolio project.
๐ก๏ธ What is an Interceptor?
An interceptor acts like a watchman on your network calls. It can:
- Log API requests and responses
- Attach tokens to headers
- Handle errors like 401/500 globally
- Retry failed requests
๐ง How to Add an Interceptor in Dio
Hereโs how to add it to your app:
// 1. Import Dio
import 'package:dio/dio.dart';
// 2. Create Dio instance and add Interceptor
final dio = Dio();
dio.interceptors.add(
InterceptorsWrapper(
onRequest: (options, handler) {
print('๐ Request: \${options.method} \${options.path}');
options.headers['Authorization'] = 'Bearer YOUR_TOKEN_HERE';
return handler.next(options);
},
onResponse: (response, handler) {
print('โ
Response: \${response.statusCode}');
return handler.next(response);
},
onError: (DioError e, handler) {
print('โ Error: \${e.message}');
return handler.next(e);
},
),
);
๐ฉ Example: Use Interceptor in Contact Form
This example hooks into your “Contact Us” form to log the submission.
ElevatedButton(
onPressed: () async {
try {
final response = await dio.post(
'https://your-api.com/contact',
data: {
'name': nameController.text,
'email': emailController.text,
'message': messageController.text,
},
);
print("โ
Message sent: \${response.statusCode}");
} catch (e) {
print("โ Error occurred: \$e");
}
},
child: Text('Submit'),
);
๐ฅ What Can You Do with Interceptors?
Add headersโ Add auth tokens globallyLog API callsโ Great for debuggingCatch errorsโ Show a snackbar or redirectRetry logicโ Handle network drops
โ Summary
- Tool: Dio + InterceptorsWrapper
- Use: Monitor, modify, handle all API calls
- Power: Centralized token + error management
๐ฏ Add this to your Flutter Web portfolio site to make your backend integration rock solid! Got questions? Drop them in the comments below ๐
Full Code
๐ Build a Contact Form with Dio Interceptor in Flutter Web
Want to take your Flutter Web portfolio to the next level? In this tutorial, you’ll learn how to integrate a contact form with Dio, use interceptors for request/response handling, and send data to an API.
๐ฆ What is Dio?
Dio is a powerful HTTP client for Flutter/Dart. It supports interceptors, global configuration, and error handling. We’ll use it to submit a contact form and log API requests using an interceptor.
๐ง What is an Interceptor?
- Intercepts every API request and response
- Can log, modify headers, and handle errors globally
- Great for adding tokens or showing messages on failures
๐ ๏ธ Full Flutter Web Example with Interceptor
This is your complete main.dart file that builds a portfolio contact page with Dio:
import 'package:flutter/material.dart';
import 'package:dio/dio.dart';
void main() {
runApp(MyPortfolioApp());
}
class MyPortfolioApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'My Flutter Web Portfolio',
theme: ThemeData(primarySwatch: Colors.blue),
home: PortfolioHomePage(),
debugShowCheckedModeBanner: false,
);
}
}
class PortfolioHomePage extends StatelessWidget {
final Dio dio = Dio();
final TextEditingController nameController = TextEditingController();
final TextEditingController emailController = TextEditingController();
final TextEditingController messageController = TextEditingController();
PortfolioHomePage() {
dio.interceptors.add(
InterceptorsWrapper(
onRequest: (options, handler) {
print("๐ค Sending Request to: ${options.uri}");
options.headers['Authorization'] = 'Bearer demoToken123';
return handler.next(options);
},
onResponse: (response, handler) {
print("โ
Response: ${response.statusCode}");
return handler.next(response);
},
onError: (DioError e, handler) {
print("โ Error: ${e.message}");
return handler.next(e);
},
),
);
}
void sendContactForm(BuildContext context) async {
try {
final response = await dio.post(
'https://your-api.com/contact',
data: {
'name': nameController.text,
'email': emailController.text,
'message': messageController.text,
},
);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text("Message Sent! Status: ${response.statusCode}")),
);
} catch (e) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text("Error sending message")),
);
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("๐งโ๐ป My Portfolio")),
body: SingleChildScrollView(
padding: EdgeInsets.all(24),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text("๐ About Me", style: Theme.of(context).textTheme.headline5),
SizedBox(height: 10),
Text("Hi! I'm a Flutter Developer passionate about UI and Web.",
style: TextStyle(fontSize: 16)),
Divider(height: 40),
Text("๐จ Contact Me", style: Theme.of(context).textTheme.headline5),
SizedBox(height: 10),
TextField(controller: nameController, decoration: InputDecoration(labelText: 'Name')),
TextField(controller: emailController, decoration: InputDecoration(labelText: 'Email')),
TextField(controller: messageController, maxLines: 4, decoration: InputDecoration(labelText: 'Message')),
SizedBox(height: 20),
ElevatedButton.icon(
onPressed: () => sendContactForm(context),
icon: Icon(Icons.send),
label: Text("Submit"),
),
],
),
),
);
}
}
๐งช How to Test This
- Run on Chrome:
flutter run -d chrome - Replace API URL with:
https://httpbin.org/postfor testing - Watch console logs for request/response
โ Summary
- ๐ฌ Dio handles form submissions
- ๐ Interceptors let you log, attach headers, and manage errors
- ๐ Flutter Web gives you a beautiful front-end for all of this
Let me know if you want the ZIP download, retry logic, or a fancier UI in the comments!
