Introduction
Loading states are a crucial part of modern mobile experiences. The skeleton_shimmer Flutter package provides a ready‑made shimmer effect and skeleton loaders that can be dropped into any widget tree with minimal boilerplate. This article walks you through when to use the package, how to install it, and how to build a production‑ready shimmer placeholder.
When Should You Use skeleton_shimmer?
Consider skeleton_shimmer when your app fetches data from a network or local database and you want to keep the UI responsive while the data arrives. Typical scenarios include:
- List or grid views that display remote items (e.g., news feeds, product catalogs).
- Detail screens where the content size is unknown until the API call completes.
- Any place where a shimmer effect is desired but you also need built‑in reduced‑motion accessibility support.
Because the package is API‑compatible with the original shimmer package, you can replace existing shimmer code with skeleton_shimmer without a major refactor.
Installation
Add the dependency to your pubspec.yaml using the Flutter CLI:
flutter pub add skeleton_shimmerAfter the command finishes, run flutter pub get (the CLI does this automatically) and import the library where you need it:
import 'package:skeleton_shimmer/skeleton_shimmer.dart';Basic Usage Example
The following example demonstrates a simple list of cards that shows a shimmer placeholder while a simulated network request loads data.
import 'package:flutter/material.dart';
import 'package:skeleton_shimmer/skeleton_shimmer.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Skeleton Shimmer Demo',
theme: ThemeData(primarySwatch: Colors.blue),
home: const HomePage(),
);
}
}
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
@override
State createState() => _HomePageState();
}
class _HomePageState extends State {
// Simulated data source – null means "loading"
List? _items;
@override
void initState() {
super.initState();
_loadData();
}
Future _loadData() async {
await Future.delayed(const Duration(seconds: 2)); // fake network latency
setState(() {
_items = List.generate(10, (i) => 'Item #${i + 1}');
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Skeleton Shimmer Demo')),
body: _items == null ? _buildShimmerList() : _buildDataList(),
);
}
Widget _buildShimmerList() {
// The SkeletonShimmer widget wraps any placeholder layout.
return ListView.builder(
itemCount: 6,
itemBuilder: (context, index) {
return SkeletonShimmer(
// You can customise colour, direction, and animation speed.
child: const ListTile(
leading: CircleAvatar(radius: 24),
title: SizedBox(height: 12, width: double.infinity),
subtitle: SizedBox(height: 8, width: 150),
),
);
},
);
}
Widget _buildDataList() {
return ListView.builder(
itemCount: _items!.length,
itemBuilder: (context, index) {
return ListTile(
leading: CircleAvatar(child: Text(_items![index][0])),
title: Text(_items![index]),
);
},
);
}
}When the screen first appears, the SkeletonShimmer widget paints a grey‑scale shimmer over the placeholder layout. After the simulated delay, the real list replaces the placeholders.
Customising the Shimmer
You can adjust the shimmer colour, speed, and direction via the widget's constructor. The package also respects the platform's reduced‑motion setting, automatically disabling animation for users who request it.
SkeletonShimmer(
baseColor: Colors.grey[300]!,
highlightColor: Colors.grey[100]!,
direction: ShimmerDirection.ltr,
period: const Duration(milliseconds: 1200),
child: MyPlaceholderWidget(),
);Integration Tips
Tip: Keep the shimmer logic behind an abstraction layer. Create a small helper widget (e.g.,
LoadingPlaceholder) that internally usesSkeletonShimmer. This makes it easier to swap the implementation later or to disable shimmer in test environments.
Common Mistakes to Avoid
- Hard‑coding the package throughout the UI. Spread of
SkeletonShimmercalls makes future refactors painful. Centralise the usage. - Ignoring reduced‑motion accessibility. The package handles it by default, but overriding
periodwith a very short duration can defeat the purpose. - Using the same placeholder size for every content type. Match the placeholder dimensions to the final widget to avoid layout jumps when data loads.
Testing Shimmer Widgets
Because shimmer animations are visual, unit tests should focus on the presence of the placeholder widget rather than the animation itself. Example using flutter_test:
testWidgets('shows shimmer while loading', (WidgetTester tester) async {
await tester.pumpWidget(const MaterialApp(home: HomePage()));
// Initial frame – shimmer should be present.
expect(find.byType(SkeletonShimmer), findsNWidgets(6));
// Fast‑forward the simulated network delay.
await tester.pump(const Duration(seconds: 2));
// After data loads, shimmer disappears.
expect(find.byType(SkeletonShimmer), findsNothing);
expect(find.text('Item #1'), findsOneWidget);
});Conclusion
The skeleton_shimmer Flutter package offers a quick, accessible way to add loading skeletons to any Flutter UI. By installing the package, wrapping your placeholder widgets with SkeletonShimmer, and following the integration best practices outlined above, you can improve perceived performance and keep your codebase maintainable.
Always verify the latest API surface and version compatibility on the official Pub page (https://pub.dev/packages/skeleton_shimmer) before shipping to production.
Frequently Asked Questions
Is skeleton_shimmer compatible with the original shimmer package?
Yes. The API is designed to be compatible with the shimmer package, so you can replace <code>Shimmer</code> widgets with <code>SkeletonShimmer</code> without major code changes.
How does skeleton_shimmer handle reduced‑motion accessibility settings?
The package automatically detects the platform's reduced‑motion preference and disables the shimmer animation, showing a static placeholder instead.
Can I customise the colours and speed of the shimmer effect?
Absolutely. <code>SkeletonShimmer</code> accepts <code>baseColor</code>, <code>highlightColor</code>, <code>direction</code>, and <code>period</code> parameters to fine‑tune the visual appearance.
Should I import skeleton_shimmer directly in every widget?
It's better to wrap the package in a small app‑specific widget (e.g., <code>LoadingPlaceholder</code>) and use that throughout your codebase. This keeps the dependency isolated and simplifies future changes.
Where can I find the latest documentation and version information?
Visit the official Pub.dev page at <a href="https://pub.dev/packages/skeleton_shimmer">https://pub.dev/packages/skeleton_shimmer</a> for up‑to‑date docs, changelogs, and migration guides.