LinearProgressIndicator in Flutter: Showing Progress Across a Width
Use Flutter's LinearProgressIndicator for determinate and indeterminate loading bars with custom colors, minHeight, and semantics.
Published on • November 4, 2026
AI Assistant

When progress spans a known width — a download bar, a multi-step wizard, a file upload — LinearProgressIndicator is the widget for the job. This follows the cited widget guide: pass a value between 0 and 1 for determinate progress, or omit it for an indeterminate animated bar.
Determinate progress
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text('Uploading… 60%'),
const SizedBox(height: 8),
const LinearProgressIndicator(value: 0.6),
],
)
The value must be between 0 and 1; values outside that range are clamped. When value is null, the bar animates back and forth to signal “in progress, length unknown.”
Styling
Use color for the filled portion, backgroundColor for the track, and minHeight to make the bar thicker:
LinearProgressIndicator(
value: 0.42,
minHeight: 8,
color: Colors.green,
backgroundColor: Colors.grey.shade200,
borderRadius: BorderRadius.circular(4),
)
borderRadius rounds both the track and the fill — a small detail that makes the bar look intentional rather than default.
Listening to progress
LinearProgressIndicator is purely visual. Drive its value from a Stream, an animation controller, or a state variable:
StreamBuilder<double>(
stream: downloadStream,
builder: (context, snapshot) {
final value = snapshot.data ?? 0;
return LinearProgressIndicator(value: value);
},
)
Semantics
The widget exposes itself to screen readers automatically. Add a label so assistive technologies announce what is loading:
Semantics(
label: 'Uploading profile photo',
child: const LinearProgressIndicator(value: 0.6),
)
Takeaway: Pass value (0–1) for determinate progress or null for indeterminate; style with color, backgroundColor, minHeight, and borderRadius, and wrap it in Semantics so screen readers know what is loading.