
skeleton_shimmer
Shimmer loading effect for Flutter, API-compatible with the shimmer
package, with skeleton placeholder widgets and reduced-motion support.
import 'package:skeleton_shimmer/skeleton_shimmer.dart';
Shimmer.fromColors(
baseColor: Colors.grey.shade300,
highlightColor: Colors.grey.shade100,
child: const Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SkeletonCircle(size: 48),
SizedBox(height: 12),
SkeletonLine(width: 220),
SizedBox(height: 8),
SkeletonLine(width: 160),
SizedBox(height: 16),
SkeletonBox(height: 120),
],
),
)
Demo

Migrating from shimmer
The widget API is the same; change the import and the class works as before:
// import 'package:shimmer/shimmer.dart';
import 'package:skeleton_shimmer/skeleton_shimmer.dart';
Shimmer, Shimmer.fromColors, ShimmerDirection (ltr, rtl,
ttb, btt), period, loop, and enabled all behave the way you
expect.
What is different
-
Reduced motion: when the platform asks for it (
MediaQuery.disableAnimations, e.g. iOS Reduce Motion), the sweep freezes on the base color instead of animating. -
Screen readers: the placeholder shapes stay out of the semantics tree, since a skeleton is decoration standing in for content that has not arrived, and a run of empty containers is nothing but an obstacle to walk past. Pass
semanticsLabelto announce the loading state instead:Shimmer.fromColors( baseColor: base, highlightColor: highlight, semanticsLabel: AppLocalizations.of(context).loading, child: const SkeletonLine(width: 200), )It works like
CircularProgressIndicator.semanticsLabel, including having no default: the package cannot invent a localized string, so it stays quiet rather than announcing English into every app. The label is a live region, so it is read when the skeleton appears rather than only when focus reaches it. -
Skeleton primitives:
SkeletonBox,SkeletonCircle, andSkeletonLinecover the usual placeholder shapes, so most screens need no custom containers. -
Tested: animation lifecycle (loop counts, enable/disable, reduced-motion transitions) and the band geometry itself (a pixel-level test asserts the sweep window matches the original) are covered by widget tests.
Skeleton primitives
| Widget | Shape |
|---|---|
SkeletonBox(width, height, borderRadius) |
Rounded rectangle |
SkeletonCircle(size) |
Circle, e.g. avatar |
SkeletonLine(width, height) |
Pill-shaped text line |
All take a color (default: a light gray for the shimmer to paint
over). Null width/height fills the available space when the
incoming constraints are bounded.
Notes
- A custom
Gradientpassed to the default constructor is used exactly as given; the sweep comes from sliding the paint window across the child, so it applies to any gradient type. loop: 0(default) repeats until the widget is disposed orenabled: false.
Credits
The API design and sweep geometry follow the shimmer package by HungHD (hnvn); this is an independent implementation.
License
MIT
Libraries
- skeleton_shimmer
- Shimmer loading effect with an API compatible with the
shimmerpackage, plus skeleton placeholder primitives and reduced-motion support.