Image Slider in Flutter with Example

The fastest way to build an image slider in Flutter is the carousel_slider package (currently v5.1.2 on pub.dev) — it gives you autoplay, dot indicators, and infinite scroll in a few lines. If you would rather avoid a dependency, Flutter's built-in PageView widget does the same job with a bit more manual setup, and newer Flutter SDKs also ship a native Material 3 CarouselView widget. Below are working examples of all three, current as of pub.dev today, plus the common mistakes and FAQ that come up when developers actually build this.
Jump to: carousel_slider package · native PageView · PageView vs carousel_slider · loading network images · common mistakes · FAQ
What Flutter Developers Call an Image Slider
The sliding image galleries you see on Amazon, Flipkart, and most onboarding screens are called carousels. In Flutter there is no single official "carousel" widget baked into the framework for older SDKs, so most apps reach for one of two approaches:
- The carousel_slider package — a purpose-built widget with autoplay, indicators, and infinite scroll ready out of the box.
- The native PageView widget — no extra dependency, more code, full control.
A note on outdated advice: older tutorials (including earlier versions of this one) recommend a package called carousel_pro. That package has not been updated in years, does not support null safety properly, and is not a safe pick for a new project in 2026. Skip it. The rest of this guide uses the actively maintained carousel_slider package instead.
Building a Slider with the carousel_slider Package
First, add the current version to pubspec.yaml and run flutter pub get:
dependencies:
flutter:
sdk: flutter
carousel_slider: ^5.1.2
Import it in your Dart file:
import 'package:carousel_slider/carousel_slider.dart';
Then build the slider. The package exposes two constructors: CarouselSlider for a fixed list of items, and CarouselSlider.builder for building slides on demand (better for long or dynamic lists).
final List<String> imageUrls = [
'https://picsum.photos/id/1015/800/400',
'https://picsum.photos/id/1016/800/400',
'https://picsum.photos/id/1018/800/400',
];
CarouselSlider(
options: CarouselOptions(
height: 220,
autoPlay: true,
autoPlayInterval: const Duration(seconds: 3),
autoPlayAnimationDuration: const Duration(milliseconds: 800),
enlargeCenterPage: true,
viewportFraction: 0.9,
onPageChanged: (index, reason) {
setState(() => _current = index);
},
),
items: imageUrls.map((url) {
return Builder(
builder: (BuildContext context) {
return ClipRRect(
borderRadius: BorderRadius.circular(12),
child: Image.network(
url,
fit: BoxFit.cover,
width: MediaQuery.of(context).size.width,
),
);
},
);
}).toList(),
)
For a list you don't know the size of ahead of time (e.g. images coming from an API), use the builder constructor instead:
CarouselSlider.builder(
itemCount: imageUrls.length,
options: CarouselOptions(height: 220, autoPlay: true),
itemBuilder: (context, index, realIndex) {
return Image.network(imageUrls[index], fit: BoxFit.cover);
},
)
Controlling the Slider Programmatically
To move slides with a button instead of a swipe, attach a CarouselSliderController (this is the current class name — older tutorials call it CarouselController, which was renamed):
final CarouselSliderController _controller = CarouselSliderController();
CarouselSlider(
carouselController: _controller,
options: CarouselOptions(height: 220),
items: imageUrls.map((url) => Image.network(url, fit: BoxFit.cover)).toList(),
)
// Elsewhere in your widget:
IconButton(
icon: const Icon(Icons.arrow_forward_ios),
onPressed: () => _controller.nextPage(
duration: const Duration(milliseconds: 300),
curve: Curves.easeInOut,
),
)
Adding Dot Indicators
carousel_slider does not draw dots for you — you either build them yourself from the onPageChanged index, or add the smooth_page_indicator package (v1.2.1) for animated ones:
List<Widget> _buildDots() {
return List.generate(imageUrls.length, (index) {
return Container(
width: 8,
height: 8,
margin: const EdgeInsets.symmetric(horizontal: 4),
decoration: BoxDecoration(
shape: BoxShape.circle,
color: _current == index ? Colors.blue : Colors.grey.shade400,
),
);
});
}
Key CarouselOptions Properties
- height — fixed slider height (skip this if you set aspectRatio instead).
- aspectRatio — width-to-height ratio, default 16:9, ignored if height is set.
- viewportFraction — how much of the screen width each slide takes up, default 0.8.
- autoPlay / autoPlayInterval / autoPlayAnimationDuration — automatic sliding controls.
- enlargeCenterPage — scales up the centered slide, the classic "peeking carousel" look.
- enableInfiniteScroll — loops back to the first slide after the last, default true.
- scrollDirection — Axis.horizontal (default) or Axis.vertical.
- onPageChanged — callback with the new index, used to drive custom dot indicators.
Building a Slider with Native PageView (No Dependency)
If you would rather not add a package, Flutter's built-in PageView widget does everything a basic carousel needs. You get full control over animation and indicators, at the cost of writing more of the logic yourself.
class ImageSlider extends StatefulWidget {
const ImageSlider({super.key});
@override
State<ImageSlider> createState() => _ImageSliderState();
}
class _ImageSliderState extends State<ImageSlider> {
final PageController _pageController = PageController(viewportFraction: 0.9);
int _currentPage = 0;
final List<String> imageUrls = [
'https://picsum.photos/id/1015/800/400',
'https://picsum.photos/id/1016/800/400',
'https://picsum.photos/id/1018/800/400',
];
@override
Widget build(BuildContext context) {
return Column(
children: [
SizedBox(
height: 220,
child: PageView.builder(
controller: _pageController,
itemCount: imageUrls.length,
onPageChanged: (index) => setState(() => _currentPage = index),
itemBuilder: (context, index) {
return ClipRRect(
borderRadius: BorderRadius.circular(12),
child: Image.network(imageUrls[index], fit: BoxFit.cover),
);
},
),
),
const SizedBox(height: 8),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: List.generate(imageUrls.length, (index) {
return AnimatedContainer(
duration: const Duration(milliseconds: 200),
margin: const EdgeInsets.symmetric(horizontal: 4),
width: _currentPage == index ? 16 : 8,
height: 8,
decoration: BoxDecoration(
color: _currentPage == index ? Colors.blue : Colors.grey.shade400,
borderRadius: BorderRadius.circular(4),
),
);
}),
),
],
);
}
}
To make a plain PageView auto-scroll, run a Timer that calls _pageController.nextPage(...) on an interval, and cancel it in dispose() — carousel_slider gives you this for free via autoPlay: true, which is the main reason people reach for the package instead of writing this by hand.
The Newest Option: Material 3 CarouselView
Recent Flutter SDKs (3.24 and up) also ship a built-in CarouselView widget as part of Material 3, with no package required. It supports weighted, multi-browse layouts (several tiles of different widths visible at once) and hero layouts out of the box. It is worth checking if your Flutter SDK is new enough before adding a dependency for a simple, Material-styled carousel — but it does not have carousel_slider's autoplay or dot-indicator conveniences built in, so most existing apps still reach for carousel_slider or PageView.
PageView vs carousel_slider vs CarouselView: Which Should You Use?
| Approach | Setup effort | Autoplay | Dot indicators | Best for |
|---|---|---|---|---|
| carousel_slider | Low — one dependency | Built in | Manual or via smooth_page_indicator | Most apps; fastest path to a working slider |
| Native PageView | Medium — you write the state | Manual (Timer) | Manual | Zero-dependency projects, custom animations |
| Material 3 CarouselView | Low, if Flutter 3.24+ | Not built in | Not built in | Material-styled multi-browse galleries |
In practice: reach for carousel_slider if you want autoplay and indicators working today with the least code. Use PageView if you want to avoid adding a dependency or need an animation carousel_slider doesn't support. Use CarouselView if your app already follows Material 3 design and you want the native multi-browse look.
Loading Images: Network vs Assets
Both approaches above work with either image source:
- Network images — use
Image.network(url), as in the examples above. Good for remote galleries, product photos, or CMS-driven content. - Bundled assets — declare the images under
flutter: assets:in pubspec.yaml, then useImage.asset('assets/images/slide1.png').
For network images, always give Image.network an errorBuilder so a failed load shows a placeholder instead of a red error box, and consider cached_network_image if the same slider re-appears often, so images aren't re-downloaded every time.
Common Mistakes When Building a Flutter Image Slider
- Using the abandoned carousel_pro package. It has not shipped an update in years and breaks under null safety. Use carousel_slider instead.
- Forgetting to give PageView a bounded height. A bare PageView inside a Column throws a layout error because it wants to expand infinitely. Wrap it in a SizedBox or Expanded.
- Not disposing the PageController or Timer. If you build auto-scroll manually with PageView, cancel the Timer and dispose the controller in your State's
dispose()method, or you'll leak memory on screens that get rebuilt often. - Setting both height and aspectRatio in CarouselOptions. height always wins, so aspectRatio is silently ignored — pick one.
- No error handling on Image.network. Without an errorBuilder, one broken image URL shows Flutter's red error box in production.
- Rebuilding the whole slide list on every autoplay tick. If your carousel wraps heavy widgets, use CarouselSlider.builder instead of the plain constructor so slides are built lazily rather than all at once.
Related reading
Frequently Asked Questions
What is the best way to build an image slider in Flutter?
For most apps, the carousel_slider package (currently v5.1.2 on pub.dev) is the fastest path — it handles autoplay, infinite scroll, and page callbacks out of the box. If you want to avoid adding a dependency, Flutter's built-in PageView widget can do the same job with more manual setup, and Flutter 3.24+ also ships a native Material 3 CarouselView widget.
Should I use PageView or carousel_slider for a Flutter carousel?
Use carousel_slider if you want autoplay and dot indicators working quickly with minimal code — it is built specifically for this. Use native PageView if you want zero extra dependencies, need a custom animation carousel_slider doesn't support, or are building something carousel_slider's options don't cover, like a fully custom transition.
What is the current version of the carousel_slider package?
carousel_slider is at version 5.1.2 on pub.dev. Older tutorials referencing carousel_slider 2.x use an outdated API and a class called CarouselController, which has since been renamed to CarouselSliderController. Always check pub.dev for the current version before pinning it in pubspec.yaml.
Is the carousel_pro package still usable in Flutter?
No. carousel_pro has not been updated in years and does not work properly with Flutter's null safety, which every modern Flutter project uses. It should not be used in new projects — carousel_slider is the actively maintained replacement for the same use case.
How do I add dot indicators to a Flutter image slider?
carousel_slider does not draw dots automatically. Track the active slide with the onPageChanged callback and build your own row of small colored containers, or add the smooth_page_indicator package (v1.2.1) for pre-built animated dot effects. With native PageView, the same approach works using the PageController's page updates.
How do I make a Flutter carousel scroll automatically?
With carousel_slider, set autoPlay: true and autoPlayInterval in CarouselOptions and it handles the rest. With native PageView, you need to run a Timer that calls pageController.nextPage() on an interval yourself, and cancel that Timer in dispose() to avoid leaking it when the widget is removed.
Can a Flutter image slider load images from the internet?
Yes. Both carousel_slider and PageView work with Image.network(url) for remote images, or Image.asset() for images bundled in the app. For network images, add an errorBuilder so a failed request shows a placeholder instead of Flutter's red error box, and consider cached_network_image if the same images reload often.
What is Flutter's Material 3 CarouselView, and should I use it instead of carousel_slider?
CarouselView is a carousel widget built directly into Flutter's Material 3 library since Flutter 3.24, so it needs no extra package. It is a good fit if your app already follows Material 3 design and wants the multi-browse, weighted-tile look. It does not include autoplay or dot indicators out of the box, though, so most existing apps that need those still use carousel_slider or a custom PageView.





