Skip to content
Blog

FL Chart: Data Visualization in Flutter from Line Charts to Radar

Building charts in Flutter with FL Chart: line, bar, pie, scatter, radar and candlestick charts; axes and grid configuration; touch interactions and tooltips; styling with gradients and animations.

Published on • September 25, 2026

AI Assistant

Every dashboard, fitness app, analytics panel, and finance product eventually needs charts — and building them with CustomPainter from scratch is a project unto itself. Axis scaling, tick placement, touch hit-testing, tooltips, and animation curves each hide a week of work. FL Chart, the most-installed charting library in the Flutter ecosystem, packages all of it behind declarative data classes.

The library describes itself as “a highly customizable Flutter chart library,” supporting Line, Bar, Pie, Scatter, Radar, and Candlestick charts. Current version is 1.2.0, MIT-licensed, with about 7.2k likes and 1.8 million downloads, running on Android, iOS, macOS, Linux, Windows, and web.

Installation

dependencies:
  fl_chart: ^1.2.0

The mental model is consistent across chart types: each chart widget takes a single *ChartData object, which holds both your data series and all configuration — axes, grid, touch behavior, styling. Everything is declarative and themeable.

Line Charts

The workhorse. LineChartData holds configuration, LineChartBarData defines a series, and FlSpot(x, y) is a data point:

LineChart(
  LineChartData(
    gridData: const FlGridData(show: true),
    titlesData: const FlTitlesData(
      bottomTitles: AxisTitles(
        axisNameWidget: Text('Month'),
        sideTitles: SideTitles(showTitles: true),
      ),
      leftTitles: AxisTitles(
        axisNameWidget: Text('Sales'),
        sideTitles: SideTitles(showTitles: true),
      ),
    ),
    borderData: FlBorderData(show: true),
    lineBarsData: [
      LineChartBarData(
        spots: const [
          FlSpot(0, 1),
          FlSpot(1, 3),
          FlSpot(2, 2),
          FlSpot(3, 5),
        ],
        isCurved: true,
        dotData: const FlDotData(show: true),
        belowBarData: BarAreaData(show: true),
      ),
    ],
  ),
)

The knobs that matter day to day:

  • isCurved switches between straight segments and smoothed curves — one boolean, and the docs’ animation guide covers animating it for draw-in effects.
  • dotData controls per-point markers, with customizable shape, size, and colors.
  • belowBarData fills the area under the line, including with a gradient — the signature “analytics dashboard” look.
  • titlesData configures all four axes independently: tick labels, axis-name widgets, intervals, and reserved size.

Multiple series is just multiple LineChartBarData entries, each independently styled.

Bar Charts

Bars group by x with one or more rods per group:

BarChart(
  BarChartData(
    alignmentSpace: 12,
    barGroups: [
      BarChartGroupData(x: 0, barRods: [
        BarChartRodData(toY: 8, width: 18),
      ]),
      BarChartGroupData(x: 1, barRods: [
        BarChartRodData(toY: 4, width: 18),
      ]),
    ],
  ),
)

BarChartGroupData is what makes grouped and stacked comparisons possible — multiple rods per group for side-by-side series, or stacked segments within a rod for composition. Rods support rounded corners, gradients, and background bars (showing a goal or maximum behind the value).

Pie Charts

Pie charts reduce to sections with values, colors, and title widgets:

PieChart(
  PieChartData(
    sections: [
      PieChartSectionData(value: 40, color: Colors.blue, title: '40%'),
      PieChartSectionData(value: 60, color: Colors.orange, title: '60%'),
    ],
  ),
)

Per-section control covers radius, inner radius (for donut charts), title styling, and badge widgets — plus sectionsSpace and centerSpaceRadius for donut styling. Pie also supports swipe-to-select via its touch data, which lifts the touched section outward — the standard “interactive donut” interaction.

Interactivity and Tooltips

Charts without touch feedback feel dead. Each chart type has its own touch data — LineTouchData, BarTouchData, PieTouchData — controlling both callbacks (which spot/rod/section was touched, for drilling into details) and built-in tooltips:

BarChartData(
  barTouchData: BarTouchData(
    touchTooltipData: BarTouchTooltipData(
      getTooltipItem: (group, groupIndex, rod, rodIndex) =>
          BarTooltipItem('${rod.toY}', const TextStyle(color: Colors.white)),
    ),
  ),
  // ...
)

The getTooltipItem/getTouchedSpotIndicator callbacks are fully programmatic — you compose the tooltip content and the indicator appearance yourself, so tooltips can carry currency formatting, units, or secondary values without fighting a template. Touch callbacks also drive selection state, so tapping a bar can filter the rest of the screen.

Styling and Theming

Nearly everything is customizable through the data classes: colors and gradients on lines, bars, and sections; grid line frequency and dashes via FlGridData; borders via FlBorderData; axis titles, intervals, and formatters via FlTitlesData; point shapes via FlDotData (including custom painters). Because configuration is plain Dart data, building a design-system chart theme is a function that returns configured LineChartData — no widget-level theming machinery needed.

The package documentation includes a dedicated animation guide, covering the standard pattern: keep chart state in a StatefulWidget, mutate the data (or swapAnimationDuration), and let FL Chart tween between old and new data. That single mechanism produces animated transitions when new data arrives, series toggling, and draw-in effects.

A live sample app with source code for every chart type runs at app.flchart.dev, with builds on Google Play and the App Store — the fastest way to find the configuration that matches a design before writing it yourself.

Choosing a Chart Type

  • Line — trends over ordered axes (time series, progress).
  • Bar — discrete comparisons (categories, periods side by side).
  • Pie/Donut — part-to-whole composition (keep the category count small).
  • Scatter — correlation between two measures.
  • Radar — multi-axis profiles (skill sets, spec comparisons).
  • Candlestick — OHLC financial data.

Performance Notes

For large datasets, a few practical habits: trim spots to the visible window when rendering thousands of points, disable dotData on dense series, prefer swapAnimationDuration tweens over rebuilding charts at animation-frame rate, and keep the chart inside a fixed-size parent so layout doesn’t re-measure per frame. The library is CustomPainter-based and generally handles hundreds of points comfortably on all six platforms.

Summary

FL Chart hits the sweet spot Flutter charting needs: declarative data classes, every chart type a dashboard asks for, touch and tooltips built in, and enough styling depth to match a design system. For the 90% case — line, bar, and donut charts with interactions — it is configuration, not painting. For the 10% that needs something bespoke, its CustomPainter patterns and the sample app are the right starting point.

References