Skip to content

Headers Reference

SmartRefresher accepts any widget as its header: prop, as long as it is a subclass of RefreshIndicator from smart_refresher. The table below maps every built-in header to its dedicated reference page.


HeaderStyleHapticsPlatform
ClassicHeaderText + icon labelAll
Material3HeaderFloating M3 cardAll
Ios17Header12-spoke tick✅ iOSAll
WaterDropHeaderFluid water dropAll
WaterDropMaterialHeaderMaterial water dropAll
BezierHeaderMorphing waveAll
BezierCircleHeaderFloating discAll
GlassHeaderFrosted glassAll

All headers share the following base properties inherited from RefreshIndicator:

PropertyTypeDefaultDescription
heightdouble60.0Height of the refresh area reserved in the scroll view.
refreshStyleRefreshStyle.followHow the header interacts with the list scroll.
completeDurationDuration600msHow long the success/failure state is shown before dismissal.

ValueDescription
.followHeader scrolls with the list content (default).
.unfollowHeader stays fixed; the list scrolls below it.
.frontHeader appears on top of the list (used by WaterDrop, Bezier).
.behindHeader is revealed behind the list as it scrolls down.

Need platform defaults? → ClassicHeader
Following Material You? → Material3Header
Building an iOS app? → Ios17Header (with haptics)
Want a playful animation? → WaterDropHeader or BezierHeader
Have a rich background image? → GlassHeader
Building a custom indicator? → See Custom Indicators guide

Any widget that extends RefreshIndicator can be used as a header. The minimum implementation:

class MyHeader extends RefreshIndicator {
const MyHeader({super.key})
: super(height: 80, refreshStyle: RefreshStyle.follow);
@override
State<StatefulWidget> createState() => _MyHeaderState();
}
class _MyHeaderState extends RefreshIndicatorState<MyHeader> {
@override
Widget buildContent(BuildContext context, RefreshStatus? mode) {
return Center(
child: switch (mode) {
RefreshStatus.idle => const Text('Pull down'),
RefreshStatus.canRefresh => const Text('Release!'),
RefreshStatus.refreshing => const CircularProgressIndicator(),
RefreshStatus.completed => const Icon(Icons.check),
_ => const SizedBox.shrink(),
},
);
}
}