A flexible and customizable carousel component for SwiftUI that works across iOS, macOS, tvOS, and visionOS.
- Horizontal scrolling carousel with smooth animations
- Auto-scroll with configurable intervals
- Infinite loop scrolling (wrap-around)
- Customizable page indicators
- Side item scaling effects
- Support for any data type (Identifiable or custom ID)
- Configurable spacing and layout
- Native swipe gestures
- Multi-platform support
Add SwiftUICarousel to your project using Xcode:
- Open your project in Xcode
- Go to File → Add Package Dependencies
- Enter the repository URL:
https://github.com/YourGitHubUsername/SwiftUICarousel.git - Select the version and click Add Package
Or add it to your Package.swift:
dependencies: [
.package(url: "https://github.com/YourGitHubUsername/SwiftUICarousel.git", from: "1.0.0")
],
targets: [
.target(
name: "YourTarget",
dependencies: ["SwiftUICarousel"]
)
]- iOS 15.0+ / macOS 12.0+ / tvOS 15.0+ / visionOS 1.0+
- Swift 5.9+
- Xcode 15.0+
Here's a simple carousel with just a few lines:
import SwiftUI
import SwiftUICarousel
struct ContentView: View {
let items = [
CarouselItem(id: 0, title: "First", color: .blue),
CarouselItem(id: 1, title: "Second", color: .green),
CarouselItem(id: 2, title: "Third", color: .orange)
]
var body: some View {
SwiftUICarousel(items) { item in
ZStack {
RoundedRectangle(cornerRadius: 16)
.fill(item.color)
Text(item.title)
.font(.title)
.foregroundColor(.white)
}
}
.frame(height: 200)
}
}
struct CarouselItem: Identifiable {
let id: Int
let title: String
let color: Color
}Here's a more complete example showing an image carousel with auto-scroll and indicators:
import SwiftUI
import SwiftUICarousel
struct CarouselDemoView: View {
private struct Item: Identifiable {
let id = UUID()
let imageURL: String
}
private let items: [Item] = (1...5).map { i in
Item(imageURL: "https://cataas.com/cat?width=800&height=600&\(i)")
}
@State private var currentIndex: Int = 0
var body: some View {
VStack {
SwiftUICarousel(
items,
index: $currentIndex,
spacing: 4,
headspace: 0,
sidesScaling: 0.85,
isWrap: true,
autoScroll: .active(5),
canMove: true,
showIndicators: true,
indicatorActiveColor: Color.init(hex: "#8C8CA1"),
indicatorInactiveColor: Color.init(hex: "#D8D8D8"),
indicatorSpacing: 8,
indicatorSize: 8
) { item in
ImageLoader(urlString: item.imageURL)
.cornerRadius(12)
}
.frame(height: 173)
.contentShape(Rectangle())
.clipped()
.padding(.horizontal, 5)
}
}
}
#Preview {
CarouselDemoView()
}@State private var currentIndex = 0
SwiftUICarousel(
items,
index: $currentIndex,
spacing: 10,
headspace: 20,
sidesScaling: 0.8,
isWrap: true,
autoScroll: .active(3),
showIndicators: true,
indicatorActiveColor: .blue,
indicatorInactiveColor: .gray.opacity(0.3)
) { item in
CustomCardView(item: item)
}
.frame(height: 250)SwiftUICarousel(
items,
isWrap: true,
autoScroll: .active(3),
showIndicators: true
) { item in
YourCustomView(item: item)
}For types that don't conform to Identifiable:
struct Product {
let sku: String
let name: String
}
let products = [
Product(sku: "A001", name: "Product 1"),
Product(sku: "A002", name: "Product 2")
]
SwiftUICarousel(products, id: \.sku) { product in
ProductCard(product: product)
}| Parameter | Type | Default | Description |
|---|---|---|---|
data |
RandomAccessCollection |
Required | The data source for the carousel |
id |
KeyPath |
\.id |
Key path to the element's identifier |
index |
Binding<Int> |
.constant(0) |
Binding to track/control current page |
spacing |
CGFloat |
10 |
Distance between adjacent items |
headspace |
CGFloat |
10 |
Width of exposed side views |
sidesScaling |
CGFloat |
0.8 |
Scale factor for side items (0...1) |
isWrap |
Bool |
false |
Enable infinite loop scrolling |
autoScroll |
SwiftUICarouselAutoScroll |
.inactive |
Auto-scroll configuration |
canMove |
Bool |
true |
Allow user interaction |
showIndicators |
Bool |
false |
Show page indicator dots |
indicatorActiveColor |
Color |
.primary |
Color for active dot |
indicatorInactiveColor |
Color |
.gray.opacity(0.5) |
Color for inactive dots |
indicatorSpacing |
CGFloat |
8 |
Spacing between dots |
indicatorSize |
CGFloat |
8 |
Size of each dot |
content |
ViewBuilder |
Required | View builder for each item |
public enum SwiftUICarouselAutoScroll: Equatable {
case inactive // No auto-scrolling
case active(TimeInterval) // Auto-scroll with interval in seconds
}Check out the Examples folder for complete, ready-to-use examples including:
- BasicExample.swift - Simple color carousel
- AutoScrollExample.swift - Auto-scrolling with indicators
- InfiniteLoopExample.swift - Infinite wrap-around
- CustomDataExample.swift - Using custom data models
- Image galleries and photo sliders
- Product showcases in e-commerce apps
- Onboarding screens and tutorials
- Promotional banners and ads
- Content highlights and featured cards
- Portfolio and work samples
- Story viewers and media galleries
Contributions are welcome! Feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/AmazingFeature) - Commit your changes (
git commit -m 'Add some AmazingFeature') - Push to the branch (
git push origin feature/AmazingFeature) - Open a Pull Request
SwiftUICarousel is available under the MIT License. See the LICENSE file for more info.
MIT License
Copyright (c) 2026 Ferdous Mahmud Akash
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
Ferdous Mahmud Akash
- Email: ferdous.webdev@gmail.com
- LinkedIn: linkedin.com/in/ferdous19
Special thanks to ACarousel for inspiration on some of the design patterns used in this library.
SwiftUICarousel is a trademark of Ferdous Mahmud Akash. All rights reserved.
