Carousel
A strip of slides you swipe or click through, from rotating hero banners to product photo galleries. Learn when carousels work, the autoplay and accessibility rules, and the swipe, dot and loading bugs testers find in almost every one.
You open a shopping app and start reading the banner: “Free delivery on orders over…” and it slides away. You tap a dot to bring it back and get a different slide. You try to scroll down past it and the page doesn’t move. Meanwhile, the app has quietly downloaded 12 MB of pictures you’ll never see.
A carousel is one of the most common components on the web and in apps, and one of the most argued about. For testers it’s a goldmine: it moves by itself, reacts to gestures, loads images, and has to stay usable for keyboard and screen reader users.
What is it?
A carousel shows one slide (or a few) at a time from a set, in a horizontal strip. Users move through it by swiping, clicking arrows, or tapping dots. Some carousels move by themselves (autoplay).
You’ll meet three main kinds:
- Hero carousels: big rotating banners at the top of a home page (“Summer sale”, “New collection”).
- Product image galleries: several photos of one product, swiped on a product page.
- Content rows: a horizontally scrolling row of cards, like “Popular near you” in a food delivery app or “Continue watching” on a streaming site.
Anatomy
- 1
Carousel region
The container. Announced as “carousel” with a label like “Featured offers”.
- 2
Slide
One item: a banner, photo or card. Only the visible slide can be focused or read.
- 3
Pause / play
Required when slides move by themselves for more than 5 seconds (WCAG 2.2.2).
- 4
Previous / next arrows
For mouse and keyboard users. At least 44×44 pt; hidden or disabled at the ends if it does not loop.
- 5
Slide counter
“2 / 5”. Must match the slide shown, every time.
- 6
Dots (slide picker)
Show the position and jump to a slide. The dot can be small; its tap area must not be.
Designs & variants
The three kinds behave differently and break differently. Try each one: swipe with a finger or drag with the mouse, use the arrows and dots, hover over the hero and watch it pause.
ShopNow
Hero carousel
Web · AppRotating promo banners at the top of a home page. Autoplays, so it needs a Pause button and must stop on hover and focus. Slides loop.
Ridge Day pack 22 L
€79.00
Product image gallery
iOS · AndroidSwipe through photos of one product. No autoplay, no loop: it has a clear start and end. A counter (2 / 5) and page dots show the position.
Content row
Material 3 · WebA horizontally scrolling row of cards. The next card peeks in to show there is more. Mouse users need arrow buttons; touch users just swipe.
When to use it
Carousels have a bad reputation, and part of it is earned. Be fair to both sides:
- The critique: hero banners get very little engagement. A widely quoted 2013 measurement from the University of Notre Dame website found that only about 1% of homepage visitors clicked a carousel slide, and most of those clicks (about 84%) went to the first slide. Usability studies (for example by the Nielsen Norman Group) also found users often skip banners because they look like ads, and get annoyed when text moves before they finish reading.
- Where carousels do work: when the user is in control and the slides are the same kind of thing: photos of a product, a row of restaurants or films, onboarding screens. Product image galleries are used heavily because people actively want to see more photos.
So carousels are a good choice when:
- The items are similar and browsable (photos, cards), and users choose to see more.
- Space is limited and a peek of the next item invites swiping.
- The first slide still works on its own, because many users never see the others.
Good and bad uses
Important info, visible
Put “Free delivery over €50” as a static banner or text near the cart, where everyone sees it.
Important info on slide 4
Hiding delivery terms, a safety recall or a price change on slide 4 of an auto-rotating hero. Most users will never see it.
User-controlled gallery
Five photos of one backpack, no autoplay, a counter “2 / 5”, swipe and arrows.
Auto-rotating wall of unrelated promos
Eight banners about different topics, changing every 3 seconds, with no pause button.
How good carousels behave
Autoplay can always be stopped
If slides move by themselves for more than 5 seconds, users must be able to pause, stop or hide them. That’s WCAGWCAGThe Web Content Accessibility Guidelines, the main international standard for accessibility.Open in glossary → success criterion 2.2.2 Pause, Stop, Hide (Level A, the minimum level). In practice a good carousel:
- Has a visible Pause/Play button, not a hidden gesture.
- Pauses on hover (mouse) and while keyboard focus is inside it.
- Stops for good once the user takes control (swipes, clicks an arrow or dot).
- Gives each slide enough time to read it: at least 5 seconds, more for longer text.
- Doesn’t autoplay when the user has asked for reduced motion (see below).
Swipe, arrows and dots all work, on every input
- Swipe on touch, and drag or arrows with a mouse. A desktop user without a trackpad can’t swipe, so arrows (or visible scroll buttons) are needed.
- A swipe needs a small threshold before it counts (the touch slopTouch slopThe small distance a finger may move before a touch counts as movement instead of a tap.Open in glossary →), so a slightly wobbly tap isn’t a swipe.
- Vertical swipes must scroll the page. A carousel only owns horizontal gestures. If you can’t scroll the page when your finger starts on the carousel, that’s a bug (a classic nested scrollingNested scrollingHow a scrollable list inside a draggable or scrollable container decides which one moves.Open in glossary → problem).
- Dots are tiny on purpose, but their tap area must not be. Aim for 44×44 pt (iOS) / 48×48 dp (Android); on the web, WCAG 2.2 asks for at least 24×24 CSS px (2.5.8, level AA). Tiny targets close together cause wrong taps.
Looping or clear ends
Either works, but be consistent:
- Looping carousels go from the last slide straight to the first, seamlessly. A visible “rewind” through all slides, a flash or a duplicated slide is a bug.
- Non-looping carousels (product galleries) have clear ends: the Previous arrow is hidden or disabled on slide 1, Next on the last slide, and a swipe past the end bounces back.
The counter and dots always tell the truth
“2 / 5”, the active dot and the slide shown must agree after a swipe, an arrow, a dot tap, autoplay, rotation and coming back from another screen. Screen readers should hear the same: “slide, 2 of 5”.
Images load smart
Carousels are heavy: five 2 MB banners is 10 MB, often on a mobile connection.
- Lazy-loadLazy loadingLoading images or content only when the user scrolls near them.Open in glossary → slides that aren’t visible yet (load the next one just before it’s needed).
- But never lazy-load the first slide: it’s often the biggest thing on the page, and delaying it hurts the Largest Contentful Paint (one of the Core Web VitalsCore Web VitalsGoogle's key page experience metrics: loading (LCP), responsiveness (INP) and visual stability (CLS).Open in glossary →).
- Serve sized images: a phone doesn’t need a 2400 px desktop banner.
Dev note
On the web that’ssrcset. - Show a placeholder with the right size while an image loads, so the page doesn’t jump.
Aspect ratio and cropping
The same image is shown in very different shapes: wide on desktop, square on a phone. Images are usually cropped to fill the slide. Text “baked into” a banner image, or a product near the edge, gets cut off. Try it:
Dev note
object-fit: cover.The headline is cut off. Text baked into the image does not survive cropping.
Things to check: is the important part (product, face, headline) visible at every breakpoint? Is the image sharp on high-density screens, or a small file stretched up? Do all slides have the same height, or does the page jump when slides change?
Common bugs
| # | Bug | What you see | Typical severity |
|---|---|---|---|
| 1 | Autoplay can’t be paused | Slides keep moving while you read, hover or tab into it | Medium–High (accessibility: fails WCAG 2.2.2) |
| 2 | Tiny or overlapping dot targets | Tapping a dot opens a different slide | Medium |
| 3 | Vertical scroll blocked | Page won’t scroll when the swipe starts on the carousel | High |
| 4 | Counter or dots out of sync | “1 / 5” on every slide, wrong dot active | Low–Medium |
| 5 | Visible loop jump | Rewinds through all slides, flashes, or shows a slide twice | Low |
| 6 | All images loaded up front | Slow first load, many MB of data on mobile | Medium |
| 7 | Bad crop or blurry image | Headline cut off on phones, pixelated banner | Medium |
| 8 | Focus lost in hidden slides | Tab goes to links on invisible slides | Medium |
| 9 | Swipe triggers a click | Dragging a slide opens the promo link | Medium |
| 10 | Layout jump | Page content jumps when slides of different heights load | Low–Medium |
Stress-test it
This is a correct carousel. Switch features on and off and watch the Autoplay status, the screen reader text and the network log. Hover over the carousel, Tab into it, drag a slide, turn on Reduced motion, and compare lazy loading and sized images on and off. Show touch targets draws the real tap areas.
Autoplay
Screen reader on the slide
“Summer sale, slide, 1 of 5”
While autoplay runs, slide changes are not announced (aria-live off). Paused, they are.
Network · images0 req · 0 KB
Find the bug
This shopping app’s home screen has a hero carousel with six bugs. Explore it like a tester:
- Watch it for a while, then try to read a slide, hover it, and stop it.
- Tap each dot and check which slide opens.
- Try to scroll the page by dragging (mouse) or swiping (touch) starting on the banner, then starting below it.
- Watch the counter and the VoiceOver text. Let it reach the last slide and see how it gets back to the first.
- Read the Network log.
🐞 Bug hunt: ShopNow home
This demo has 6 hidden bugs. Explore it like a tester, then check your findings.
ShopNow
Categories
Popular now
- Trail runner 2€129
- Ridge day pack€79
- Dome tent 2P€189
- Sun hat€24
- Merino tee€49
- Camp mug€12
You’ve reached the end · Help · Returns
With a mouse, drag the screen up and down like a finger. On a phone, just swipe.
VoiceOver on the banner
“Summer sale. Slide 1 of 5.”
Network (app launch)0 req · 12.4 MB
- 1
Hint: Try to read a slide. Hover over it. Look for a pause button.
- 2
Hint: Tap the first dot, then the second. Which slide appears?
- 3
Hint: Drag (or swipe) upwards starting on the banner, then starting on the products.
- 4
Hint: Watch the counter in the corner and the VoiceOver text while slides change.
- 5
Hint: Wait for the last slide (Gift cards) and watch the next change.
- 6
Hint: Read the Network log right after starting the app.
How to test it
Checklist
Carousel test checklist
0 of 15 checked
Example test cases
TC-CAR-001Autoplay can be paused with the Pause buttonpositivehigh
Steps
- Open Home and watch the hero carousel change once
- Tap the Pause button
- Wait 20 seconds
Expected result
The slide stays the same. The button changes to Play with the label "Start automatic slide show".
TC-CAR-002Autoplay pauses on hover and keyboard focus (web)positivemedium
Steps
- Hover the mouse over the carousel for 15 seconds
- Move the mouse away
- Press Tab until focus reaches a carousel control and wait 15 seconds
Expected result
The carousel does not move while hovered or focused, and resumes only after hover or focus leaves it (unless the user paused it).
TC-CAR-003Vertical swipe on the carousel scrolls the pagepositivehigh
Preconditions
- Real phone, Home screen at the top
Steps
- Put a finger on the carousel and swipe up
- Swipe up diagonally (mostly vertical)
Expected result
The page scrolls both times. The carousel does not change slide on a mostly vertical swipe.
TC-CAR-004Each dot opens its own slidepositivemedium
Steps
- Pause autoplay
- Tap dot 1, 2, 3, 4, 5 in turn, with a finger
Expected result
Each tap shows the matching slide, the dot becomes active and the counter matches.
TC-CAR-005Seamless loop from last to firstedgelow
Steps
- Go to the last slide
- Tap Next (or swipe left)
Expected result
Slide 1 slides in from the right, like any other step. No rewind, flash or duplicate slide.
TC-CAR-006Only the needed images load on first viewpositivemedium
Preconditions
- DevTools › Network, filter "Img", cache disabled, Fast 4G throttling
Steps
- Load the home page
- Do not touch the carousel
- Then go to slide 2 and 3
Expected result
On load only slide 1 (and at most slide 2) is requested, in a size close to the displayed width. Later slides are requested as you approach them.
TC-CAR-007Reduced motion disables autoplayedgemedium
Preconditions
- iOS: Settings › Accessibility › Motion › Reduce Motion on
Steps
- Open Home
- Wait 20 seconds
- Swipe to the next slide
Expected result
Slides do not change by themselves. Swiping still works, without a long sliding animation.
TC-CAR-008Screen reader announces slide positionpositivemedium
Steps
- Turn on VoiceOver or TalkBack
- Move to the carousel
- Go to the next slide
Expected result
The carousel is announced with its name ("Featured offers") and each slide as "slide, 2 of 5". Content of hidden slides is not read.
Tip: click a test case to expand it.
Tools
- Real devices: gestures, scrolling conflicts and tap accuracy only show up with a real finger. See Gestures.
- DevTools › Network (filter Img) with network throttlingNetwork throttlingDeliberately slowing the connection to test how an app behaves on poor networks.Open in glossary →: count the requests and MB on first load. Lighthouse flags oversized images and a lazy-loaded LCP image. See Performance basics.
- DevTools › Rendering: emulate
prefers-reduced-motion. Elements: inspect the dot buttons to see their real size. - Responsive mode (Responsive design testing): check the crop at 360, 768 and 1440 px wide.
- Screen readers: VoiceOver (iOS/macOS), TalkBack (Android), NVDA (Windows).
Accessibility
- Name and role. The container is a region announced as a carousel with a label. Each slide is a group announced as “slide” with its position (“2 of 5”).
Dev note
For example<section aria-roledescription="carousel" aria-label="Featured offers">. This follows the WAI-ARIA Authoring Practices carousel pattern (ARIAARIAHTML attributes that tell assistive technology what custom elements are and what state they're in.Open in glossary →). - Pause control first. The Pause/Play button should come first in the focus orderFocus orderThe order in which the Tab key moves through interactive elements.Open in glossary →, so keyboard and screen reader users can stop the motion before anything else.
- Don’t move focus unexpectedly. Changing slides (by autoplay or a click) must not move keyboard focus. Links and buttons on hidden slides must not be focusable.
Dev note
Useinertortabindex="-1"plusaria-hidden. - Announce changes only when the user caused them. Otherwise screen readers interrupt the user every few seconds.
Dev note
Usearia-live="polite"on the slides while autoplay is off, andaria-live="off"while it runs. - Labeled controls. “Previous slide”, “Next slide”, “Go to slide 3” (or the slide’s name), “Stop automatic slide show”.
- Alt textAlt textA text description of an image that screen readers read aloud.Open in glossary → for every meaningful image, including text that is baked into a banner (“Summer sale: up to 40% off sandals”).
- Touch targetsTouch targetThe area of the screen that responds to a tap, which should be large enough for a finger.Open in glossary →: arrows and dots at least 44×44 pt / 48×48 dp. Swiping is optional: every slide must be reachable with a tap or a key.
- Contrast: text over images needs 4.5:1 against the actual pixels behind it, on every slide. A gradient overlay usually helps.
Mobile vs web
- No ready-made “carousel” control.
Dev note
Apps build it with a pagingUICollectionView/UIScrollView, or SwiftUITabViewwith.tabViewStyle(.page), plusUIPageControlfor the dots. - Test the edge swipe: on a carousel at the left edge, swiping right may trigger the system Back gesture instead.
- Test Reduce Motion, VoiceOver (can you reach and hear every slide? Is the position announced?) and Dynamic Type on slide text.
- Material 3 has a Carousel component (multi-browse, uncontained, hero and full-screen layouts).
Dev note
Older apps useViewPager2or ComposeHorizontalPager. - Test inside nested scrolling containers (a carousel inside a vertical list inside tabs): which one wins the gesture?
- Test Remove animations, TalkBack, rotation (does it keep the slide?) and process death.
- Quality of web carousels varies a lot, so check the accessibility basics yourself.
Dev note
Usually a JavaScript library (Swiper, Splide, Slick, Embla…) or CSS scroll snap. - Test with mouse only (no horizontal wheel): can you reach every slide? With keyboard only: Tab order, visible focus, no hidden focus traps.
- Check image loading in DevTools, the crop at several widths, and
prefers-reduced-motion. - Check layout shift: does content below jump when the carousel’s images load?
Check your understanding
Quick quiz
0/6 answered · 0 correct
1.A hero carousel changes slide every 4 seconds and has no way to stop it. Which WCAG criterion does it fail?
2.You swipe up on a banner carousel to scroll the page, but nothing moves. What is this?
3.Which slide image should NOT be lazy-loaded?
4.Which carousel type do users engage with the most?
5.Tapping the first dot of a carousel opens slide 2. What should you check first?
6.The user has turned on Reduce Motion. What should an autoplaying carousel do?
Key takeaways
- Carousels work when users are in control (product galleries, content rows). Auto-rotating hero banners get little engagement, so don’t hide important info on later slides.
- Autoplay needs a visible Pause button, must pause on hover and focus, stop after interaction, and stay off with reduced motion (WCAG 2.2.2).
- A carousel owns only horizontal gestures: vertical swipes must still scroll the page.
- Counter, dots and slide must always match, for eyes and for screen readers (“2 of 5”).
- Test dot tap areas, loop behavior and ends, with a real finger.
- Images: lazy-load later slides, never the first; serve sized images; check the crop at every width.
Finished this page?Nice work, this page is complete!
Mark it as done to track your progress. It's saved in this browser, no account needed.
Its review cards are now in Bites ⚡