Use FlutterFlow's PageView widget configured for horizontal scrolling to build a swipeable carousel. Each child is a Container with a background Image, gradient overlay, and text. Add dot indicators using a Row of Containers with Conditional Styling tied to the PageView Controller's current page index. Enable auto-scroll with an On Page Load loop action that waits three seconds then animates to the next page.
Building a Swipeable Carousel in FlutterFlow
Carousels are used for hero banners, onboarding slides, product showcases, and promotional content. FlutterFlow's PageView widget is the foundation for building carousels — it supports horizontal swiping, page snapping, and controller-based navigation. This tutorial builds a complete image carousel with indicators and auto-scroll.
Prerequisites
- A FlutterFlow project open in the builder
- Images for carousel slides (uploaded as assets or hosted URLs)
- A Firestore collection for dynamic slides (optional)
Step-by-step guide
Add a PageView widget configured for horizontal scrolling
Add a PageView widget configured for horizontal scrolling
Drag a PageView widget from the Widget Palette onto your page. In the Properties Panel, set Scroll Direction to Horizontal and enable Page Snapping. Set the height to your desired slide height (e.g., 220 for a banner or 400 for a hero). Leave width at infinity to fill the parent. PageView creates multiple children pages that the user swipes between, each snapping into place.
Expected result: A horizontal PageView appears on the page that can hold multiple slide children.
Design each carousel slide with an image, gradient, and text overlay
Design each carousel slide with an image, gradient, and text overlay
Inside the PageView, add a Container child for each slide. Set the Container's decoration to an Image background (choose your slide image as a DecorationImage with BoxFit.cover). Add a second decoration layer: a linear gradient from transparent at the top to black at 60% opacity at the bottom. Inside the Container, add a Column (mainAxisAlignment: end) with a Text widget for the slide title (white, Headline Small) and a subtitle Text (white, Body Small). This creates a professional image card with readable text over the gradient.
Expected result: Each slide shows a full-bleed image with a bottom gradient and white text overlay.
Add dot indicators below the carousel tied to the active page
Add dot indicators below the carousel tied to the active page
Below the PageView, add a Row with mainAxisAlignment set to center. Add one small Container per slide (width 8, height 8, borderRadius 4 for a circle). For the active dot, use a wider Container (width 24) with your Primary theme color. Set Conditional Styling on each dot: if the PageView Controller's current page index equals this dot's index, apply the active style (wider, colored). Otherwise, apply the inactive style (small, grey). Bind the page index using the PageView's controller reference.
Expected result: Dots below the carousel highlight the currently active slide and update as the user swipes.
Enable auto-scroll with a timed loop in On Page Load
Enable auto-scroll with a timed loop in On Page Load
Open the Action Flow for the page's On Page Load trigger. Add a Loop action with a large iteration count (e.g., 999). Inside the loop body, add a Wait action set to 3000 milliseconds (3 seconds). After the wait, add an Animate to Next Page action targeting your PageView widget (select it by name). If the PageView is on the last page, it cycles back to the first. This creates an infinite auto-scrolling carousel that still allows manual swiping.
Expected result: The carousel automatically advances to the next slide every 3 seconds, cycling back to the first after the last slide.
Populate slides dynamically from a Firestore banners collection
Populate slides dynamically from a Firestore banners collection
Create a Firestore collection called banners with fields: title (string), subtitle (string), imageUrl (string), actionUrl (string), order (int). Add documents for each slide. On the PageView, enable Generate Dynamic Children and bind it to a Backend Query on the banners collection sorted by order ascending. Map each child Container's image to the imageUrl field, title Text to the title field, and add an On Tap action that uses Launch URL with the actionUrl field.
Expected result: Carousel slides are generated from Firestore data and can be updated without modifying the app.
Complete working example
1WIDGET TREE:2 Column3 ├── PageView (height: 220, horizontal, page snapping: on)4 │ ├── Container (slide 1)5 │ │ ├── Decoration: Image (banner1.jpg, BoxFit.cover)6 │ │ ├── Decoration: LinearGradient (transparent → black 60%)7 │ │ └── Column (mainAxisAlignment: end)8 │ │ ├── Padding (16px)9 │ │ ├── Text: "Summer Sale" (white, Headline Small)10 │ │ └── Text: "Up to 50% off" (white, Body Small)11 │ ├── Container (slide 2) ... same structure12 │ └── Container (slide 3) ... same structure13 └── Padding (top: 12)14 └── Row (mainAxisAlignment: center, spacing: 6)15 ├── Container (active dot: w24 h8, borderRadius 4, Primary color)16 ├── Container (inactive dot: w8 h8, borderRadius 4, grey)17 └── Container (inactive dot: w8 h8, borderRadius 4, grey)1819DOT INDICATOR CONDITIONAL STYLING:20 Each dot checks: PageView.currentPage == thisIndex21 Active: width 24, color Theme.primary22 Inactive: width 8, color grey3002324AUTO-SCROLL ACTION FLOW (On Page Load):25 1. Loop (iterations: 999)26 a. Wait: 3000ms27 b. Animate to Next Page (target: PageView)2829FIRESTORE DATA MODEL (for dynamic slides):30 Collection: banners31 Fields: title, subtitle, imageUrl, actionUrl, order (int)32 Query: order ascendingCommon mistakes when creating a Custom Carousel for Your FlutterFlow App
Why it's a problem: Setting a fixed height without considering image aspect ratios
How to avoid: Use images with a consistent aspect ratio (e.g., all 16:9). Set the PageView height to match that ratio relative to the screen width. Crop images before uploading.
Why it's a problem: Not enabling Page Snapping on the PageView
How to avoid: Enable Page Snapping in the PageView Properties Panel so each swipe lands precisely on a full slide.
Why it's a problem: Hardcoding slide content instead of using dynamic data
How to avoid: Store slide data in a Firestore banners collection and use Generate Dynamic Children on the PageView. Updates happen instantly without app changes.
Best practices
- Use Page Snapping on the PageView so slides land precisely on each swipe
- Add a gradient overlay on image slides so white text is always readable
- Keep auto-scroll interval between 3 and 5 seconds — too fast is disorienting
- Store carousel content in Firestore for easy marketing team updates
- Use consistent image aspect ratios across all slides to prevent cropping issues
- Make dot indicators wide for active and small for inactive to clearly show position
- Add On Tap actions on slides to make them tappable for promotions or navigation
Still stuck?
Copy one of these prompts to get a personalized, step-by-step explanation.
I want to build a swipeable image carousel in FlutterFlow using PageView with dot indicators and auto-scroll. Each slide has a background image with gradient overlay and text. Explain the widget tree, dot indicator logic, and auto-scroll timer setup.
Add a PageView to my page, set to horizontal scrolling with page snapping. Add three Container children inside it, each filling the full width and 220px height.
Frequently asked questions
Can I use the carousel for onboarding screens?
Yes. Use the same PageView + dot indicator pattern for onboarding. Add a Skip button and a Done button on the last slide instead of auto-scroll.
How do I make the carousel loop infinitely?
FlutterFlow's built-in Animate to Next Page wraps to the first slide after the last. For seamless infinite scroll without visible wrap, you need a Custom Widget with a PageController that jumps back programmatically.
Can I add different tap actions to each slide?
Yes. When using dynamic children from Firestore, include an actionUrl field in each banner document. On the Container's On Tap, use Launch URL or Navigate with the actionUrl value.
Does auto-scroll stop when the user manually swipes?
No — the loop continues running. To pause on user interaction, you would need a Custom Widget that listens to PageController scroll events and pauses the timer.
How many slides should a carousel have?
Best practice is 3 to 5 slides. More than 5 means most users never see the later slides. If you have more content, consider a different layout like a grid or list.
Can RapidDev help build an advanced carousel component?
Yes. RapidDev can create a Custom Widget carousel with infinite loop, pause-on-touch, swipe velocity detection, and parallax effects that go beyond the built-in PageView.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation