Flutter Segmented Button and Badge — Custom Implementation
Teqani Blogs
Writer at Teqani
Flutter keeps evolving with every release, introducing smarter and cleaner UI widgets to speed up development. This article explores how to use SegmentedButton and Badge in a custom, reusable, and responsive way that fits any Flutter project. Learn how to create dynamic filters and status indicators with minimal effort, ensuring a clean, scalable, and platform-responsive Flutter project.
What are SegmentedButton and Badge?
SegmentedButton lets users toggle between multiple options (like filters or modes) in a compact layout.
Badge helps display notification counts, message indicators, or alerts on top of icons.
These widgets were officially introduced in Flutter 3.7+, replacing custom toggle patterns we used to manually create with ToggleButtons or Container widgets.
SegmentedButton — Custom Example
Segmented Button 🔹 Reusable Implementation
class CustomSegmentedButton extends StatefulWidget {
 final List<String> segments;
 final Function(String) onChanged;
 final String initialValue;
 const CustomSegmentedButton({
 super.key,
 required this.segments,
 required this.onChanged,
 required this.initialValue,
 });
 @override
 State<CustomSegmentedButton> createState() => _CustomSegmentedButtonState();
}
class _CustomSegmentedButtonState extends State<CustomSegmentedButton> {
 late String selectedValue;
 @override
 void initState() {
 super.initState();
 selectedValue = widget.initialValue;
 }
 @override
 Widget build(BuildContext context) {
 return SegmentedButton<String>(
 segments: widget.segments
 .map((e) => ButtonSegment<String>(
 value: e,
 label: Text(e, style: const TextStyle(fontSize: 14)),
 ))
 .toList(),
 selected: {selectedValue},
 onSelectionChanged: (newSelection) {
 setState(() => selectedValue = newSelection.first);
 widget.onChanged(selectedValue);
 },
 style: ButtonStyle(
 backgroundColor: MaterialStateProperty.resolveWith((states) =>
 states.contains(MaterialState.selected)
 ? Colors.blue.shade100
 : Colors.grey.shade200),
 side: MaterialStateProperty.all(
 const BorderSide(color: Colors.blueAccent)),
 ),
 );
 }
}
✅ Usage Example
CustomSegmentedButton(
 segments: const ['Active', 'Inactive', 'All'],
 initialValue: 'Active',
 onChanged: (value) {
 debugPrint('Selected: $value');
 },
),
Badge — Custom Example
Badge 🔹 Reusable Badge Widget
class CustomBadge extends StatelessWidget {
 final int count;
 final Widget icon;
 final Color? color;
 const CustomBadge({
 super.key,
 required this.count,
 required this.icon,
 this.color,
 });
 @override
 Widget build(BuildContext context) {
 return Badge.count(
 count: count,
 backgroundColor: color ?? Colors.redAccent,
 alignment: Alignment.topEnd,
 child: icon,
 );
 }
}
✅ Usage Example
CustomBadge(
 count: 5,
 icon: const Icon(Icons.notifications, size: 28),
),
Combine Both Widgets
You can use both together in dashboards or filter sections:
Row(
 mainAxisAlignment: MainAxisAlignment.spaceBetween,
 children: [
 CustomSegmentedButton(
 segments: const ['Today', 'Week', 'Month'],
 initialValue: 'Today',
 onChanged: (v) => debugPrint(v),
 ),
 CustomBadge(
 count: 3,
 icon: const Icon(Icons.mail_outline),
 ),
 ],
)
Responsive Tip
Wrap in LayoutBuilder or use Flexible in Row/Column to make it adaptive for mobile and web.
Why Use Custom Widgets?
- Reusable across multiple screens
 - Easier to maintain and style consistently
 - Clean separation of logic and UI
 - Ready for theming and dynamic data updates
 
Conclusion
The SegmentedButton and Badge widgets in Flutter make modern UI interactions effortless—and when wrapped in reusable custom widgets, they become even more powerful.
By creating modular components like CustomSegmentedButton and CustomBadge, you can keep your Flutter project clean, scalable, and responsive across platforms.
What’s Next?
You can extend these widgets by:
- Adding icons in SegmentedButton labels
 - Animating the badge count
 - Integrating with Riverpod or Bloc for real-time updates
 
All blogs are certified by our company and reviewed by our specialists
Issue Number: #ab94b6b8-c3d9-4795-8c44-e27a2183a973