Create interactive charts in FlutterFlow using a Custom Widget with the fl_chart package. Build three chart types: bar charts for category comparisons, line charts for trends over time, and pie charts for proportional data. Pass chart data from Firestore via Component Parameters as a JSON list. Configure axes, labels, colors, animations, and touch interactions for tooltips. Each chart requires a Container with fixed height because fl_chart needs bounded constraints.
Adding Charts and Data Visualization to Your FlutterFlow App
Data visualization helps users understand metrics, trends, and distributions at a glance. FlutterFlow does not have built-in chart widgets, so we use the fl_chart package in a Custom Widget. This tutorial covers the three most common chart types.
Prerequisites
- FlutterFlow Pro plan or higher (Custom Code required)
- Firestore data to visualize (sales, metrics, categories, etc.)
- Basic understanding of Custom Widgets and Component Parameters
Step-by-step guide
Add the fl_chart dependency to your project
Add the fl_chart dependency to your project
Go to Custom Code → Pubspec Dependencies and add fl_chart with version ^0.66.0. Click Save. fl_chart is the most popular Flutter charting library with support for bar, line, pie, scatter, and radar charts. All charts are customizable with colors, labels, animations, and touch interactions.
Expected result: The fl_chart package is available for import in Custom Widgets.
Create a bar chart Custom Widget for category comparisons
Create a bar chart Custom Widget for category comparisons
Create a Custom Widget called BarChartWidget with parameters: dataJson (String, JSON array of {label, value, color}), height (double, default 300). In the widget, parse the JSON, create BarChartGroupData for each item with x position and BarRodData containing the y value and color. Configure BarChartData with titlesData for x-axis labels (SideTitleWidget from each item's label) and y-axis values. Wrap in a Container with the specified height.
1import 'package:fl_chart/fl_chart.dart';2import 'dart:convert';34class BarChartWidget extends StatelessWidget {5 const BarChartWidget({super.key, this.width, this.height, required this.dataJson});6 final double? width;7 final double? height;8 final String dataJson;910 @override11 Widget build(BuildContext context) {12 final items = (jsonDecode(dataJson) as List).cast<Map<String, dynamic>>();13 return SizedBox(14 width: width ?? double.infinity,15 height: height ?? 300,16 child: BarChart(17 BarChartData(18 barGroups: items.asMap().entries.map((e) {19 return BarChartGroupData(x: e.key, barRods: [20 BarChartRodData(21 toY: (e.value['value'] as num).toDouble(),22 color: Color(int.parse(e.value['color'] ?? '0xFF4B39EF')),23 width: 20,24 borderRadius: BorderRadius.vertical(top: Radius.circular(4)),25 ),26 ]);27 }).toList(),28 titlesData: FlTitlesData(29 bottomTitles: AxisTitles(sideTitles: SideTitles(30 showTitles: true,31 getTitlesWidget: (value, meta) => Text(items[value.toInt()]['label'], style: TextStyle(fontSize: 10)),32 )),33 ),34 ),35 ),36 );37 }38}Expected result: A bar chart renders with labeled categories and colored bars from the JSON data.
Create a line chart Custom Widget for trend visualization
Create a line chart Custom Widget for trend visualization
Create LineChartWidget with parameters: dataJson (String, JSON array of {x, y} points). Parse the JSON and create FlSpot objects. Build LineChartBarData with the spots, curve type (isCurved: true for smooth, false for straight), color, and dotData configuration. Set titlesData for axis labels. Enable FlTouchData with LineTouchData for tooltips — when users tap a point, show the value.
Expected result: A line chart renders with connected data points, smooth curves, and touch tooltips.
Create a pie chart Custom Widget for proportional data
Create a pie chart Custom Widget for proportional data
Create PieChartWidget with parameters: dataJson (String, JSON array of {label, value, color}). Parse and create PieChartSectionData for each item: value as the section value, color from the data, title as the label, titleStyle in white. Set centerSpaceRadius to 40 for a donut chart or 0 for a full pie. Add a legend below using a Row or Wrap of colored circle + label Text pairs.
Expected result: A donut or pie chart renders with colored sections, labels, and a legend below.
Pass Firestore data to charts via a Backend Query and Component Parameter
Pass Firestore data to charts via a Backend Query and Component Parameter
On your dashboard page, add a Backend Query for your analytics data (e.g., a sales_monthly collection). Format the query results into the JSON string format the chart expects using a Custom Function. Pass the formatted JSON string to the chart widget's dataJson Component Parameter. When the query updates (e.g., date filter changes), the chart re-renders with new data automatically.
Expected result: Charts display real Firestore data and update when the underlying data changes.
Complete working example
1import 'package:fl_chart/fl_chart.dart';2import 'dart:convert';3import 'package:flutter/material.dart';45class BarChartWidget extends StatelessWidget {6 const BarChartWidget({7 super.key,8 this.width,9 this.height,10 required this.dataJson,11 });1213 final double? width;14 final double? height;15 final String dataJson;1617 @override18 Widget build(BuildContext context) {19 final items = (jsonDecode(dataJson) as List)20 .cast<Map<String, dynamic>>();2122 return SizedBox(23 width: width ?? double.infinity,24 height: height ?? 300,25 child: Padding(26 padding: const EdgeInsets.all(16),27 child: BarChart(28 BarChartData(29 alignment: BarChartAlignment.spaceAround,30 maxY: items.fold<double>(31 0, (max, i) => (i['value'] as num).toDouble() > max32 ? (i['value'] as num).toDouble()33 : max) * 1.2,34 barGroups: items.asMap().entries.map((entry) {35 final color = entry.value['color'] != null36 ? Color(int.parse(entry.value['color']))37 : Theme.of(context).primaryColor;38 return BarChartGroupData(39 x: entry.key,40 barRods: [41 BarChartRodData(42 toY: (entry.value['value'] as num).toDouble(),43 color: color,44 width: 24,45 borderRadius: const BorderRadius.vertical(46 top: Radius.circular(6),47 ),48 ),49 ],50 );51 }).toList(),52 titlesData: FlTitlesData(53 topTitles: const AxisTitles(54 sideTitles: SideTitles(showTitles: false)),55 rightTitles: const AxisTitles(56 sideTitles: SideTitles(showTitles: false)),57 bottomTitles: AxisTitles(58 sideTitles: SideTitles(59 showTitles: true,60 getTitlesWidget: (value, meta) {61 final idx = value.toInt();62 if (idx < 0 || idx >= items.length) return const SizedBox();63 return Padding(64 padding: const EdgeInsets.only(top: 8),65 child: Text(66 items[idx]['label'] ?? '',67 style: const TextStyle(fontSize: 11),68 ),69 );70 },71 ),72 ),73 ),74 gridData: const FlGridData(show: true, drawVerticalLine: false),75 borderData: FlBorderData(show: false),76 barTouchData: BarTouchData(77 touchTooltipData: BarTouchTooltipData(78 getTooltipItem: (group, groupIdx, rod, rodIdx) {79 return BarTooltipItem(80 rod.toY.round().toString(),81 const TextStyle(82 color: Colors.white,83 fontWeight: FontWeight.bold,84 ),85 );86 },87 ),88 ),89 ),90 swapAnimationDuration: const Duration(milliseconds: 300),91 ),92 ),93 );94 }95}Common mistakes when implementing Custom Data Visualizations in FlutterFlow
Why it's a problem: Not setting a fixed height on the chart Container
How to avoid: Always set a specific height on the Container or SizedBox wrapping the chart (typically 250-400px).
Why it's a problem: Passing raw Firestore data without formatting to JSON
How to avoid: Use a Custom Function to transform Backend Query results into the JSON format expected by the chart ({label, value, color} for bar/pie, {x, y} for line).
Why it's a problem: Loading too many data points in a line chart
How to avoid: Aggregate data before charting — show daily averages instead of per-minute values, or weekly totals instead of daily. Aim for 10-30 data points per chart.
Best practices
- Set a fixed height on every chart Container to prevent layout errors
- Pass data as JSON strings via Component Parameters for flexible data binding
- Add touch interactions (BarTouchData, LineTouchData) for tooltips on tap
- Use animations (swapAnimationDuration) for smooth data transitions
- Aggregate data to 10-30 points for readable charts
- Add a legend Component below pie charts for section identification
- Format axis labels clearly — abbreviated months, rounded numbers
Still stuck?
Copy one of these prompts to get a personalized, step-by-step explanation.
I want to add bar charts, line charts, and pie charts to my FlutterFlow app using the fl_chart package. Create Custom Widgets for each chart type that accept data as JSON Component Parameters. Include axis labels, colors, animations, and touch tooltips.
Add a Container with 300px height for a chart area on my dashboard page. I will add the Custom Widget chart inside it.
Frequently asked questions
Does fl_chart support real-time updating?
Yes. When you update the data passed to the widget (via Page State change), fl_chart animates the transition between old and new values. Set swapAnimationDuration for the transition speed.
Can I create a horizontal bar chart?
fl_chart's BarChart does not natively support horizontal orientation. Use the rotatedBarChart configuration or rotate the widget with Transform.rotate.
Can I export charts as images?
Yes. Wrap the chart in a RepaintBoundary widget. Use the boundary's toImage() method in a Custom Action to capture the chart as a PNG for sharing or saving.
What is the best chart type for my data?
Bar charts: comparing categories. Line charts: trends over time. Pie charts: proportional breakdown of a total. Scatter charts: correlation between two variables.
Can I add multiple lines to one line chart?
Yes. Add multiple LineChartBarData entries to the lineBarsData list. Each line can have its own color and style for comparison.
Can RapidDev help build data dashboards?
Yes. RapidDev can build analytics dashboards with multiple chart types, date filters, KPI cards, and real-time data integration.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation