Skip to content

camosss/TabPagerX

Repository files navigation

TabPagerX

Swift Version Release Version SPM CocoaPods

Effortless SwiftUI tab pager with dynamic customization.

TabPagerX is a SwiftUI-based library designed to help iOS developers create customizable tab pagers with ease. It offers flexible layouts, tab scroll preservation, and extensive styling options for tab buttons and indicators, making it a perfect choice for building tab-based navigation in your SwiftUI applications.


πŸ’₯ Features

  • Generic Data API: Work with any Identifiable & Equatable data model.
  • Type-safe Builders: Closure-based content and tabTitle per item.
  • Static & Dynamic Tabs: Supports both fixed arrays and API-driven dynamic lists.
  • Configurable Layouts: Fixed/Scrollable tab bar with spacing and padding controls.
  • Indicator Customization: Height, color, corner radius, horizontal inset, animation.
  • Optional Separator: Built-in separator between TabBar and content via modifier.
  • Gesture Navigation: Enable/disable swipe between pages.

πŸ’₯ Requirements

  • iOS 15.0+
  • Swift 5.5+
  • Xcode 15.0+

πŸ’₯ Usage

Getting Started

  • Bind a @State variable to selectedIndex to track the current tab.
  • Optionally set initialIndex (default is 0) to define which tab is shown first (applied once on first appearance).
  • Provide items (any Identifiable & Equatable type).
  • Define each tab's content using SwiftUI views via content closure.
  • Use tabTitle closure to provide a custom tab label per item (@ViewBuilder).

Note (Dynamic/API-driven tabs): When tabs are loaded asynchronously (e.g., isLoading == true), guard against out-of-range indices until data is ready.

  • Render a placeholder while loading, or when items.isEmpty.
  • Safety for async loading and index clamping will be improved in a future update.
@State private var selectedIndex = 0
@State private var isLoading = true
@State private var items: [Item] = []

var body: some View {
    Group {
        if isLoading || items.isEmpty {
            ProgressView()
        } else {
            TabPagerX(
                selectedIndex: $selectedIndex,
                items: items
            ) { item in
                /* content */
            } tabTitle: { item, isSelected in
                /* title */
            }
        }
    }
}

Same Content (all items share the same view)

  • Ideal for simple static lists or repeating the same layout.
  • All tabs use the same view
Same Content Example 1 Same Content Example 2
@State private var selectedIndex = 0
private let items = [..]

TabPagerX(
    selectedIndex: $selectedIndex,
    initialIndex: 0, // optional
    items: items
) { item in
    Text(item.content)
    ...
    
} tabTitle: { item, isSelected in
    Text(item.title)
}
.tabBarLayoutStyle(.scrollable)

Different Views by Type (render different view per type)

  • Renders different views based on each item's type.
  • Useful when each tab needs heterogeneous UI
Different Views - Image 1 Different Views - Image 2
@State private var selectedIndex = 0
private let items = [..]

TabPagerX(
    selectedIndex: $selectedIndex,
    items: items
) { item in
    switch item.type {
    case .text(let text):
        Text(text)
    case .image(let name):
        Image(systemName: name)
    case .custom:
        CustomView()
    }
    ...
    
} tabTitle: { item, isSelected in
    HStack {
        if case .image = item.type {
            Image(systemName: "photo")
        } else if case .text = item.type {
            Image(systemName: "star.circle")
        }
        Text(item.title)
    }
}

For more examples, see TabPagerXSample in the sample app. (link: TabPagerXSample)


πŸ’₯ Configuration

layoutStyle

  • Set Tab Bar Layout Style
  • Choose between fixed or scrollable layouts.
  • Custom tab views are fully supported in both layouts.
.tabBarLayoutStyle(.fixed)
Fixed layout screenshot
.tabBarLayoutStyle(.scrollable)
Scrollable layout screenshot

layoutConfig

  • Configure Tab Bar Layout
  • Adjust buttonSpacing and sidePadding. (defaults to 0)
    • buttonSpacing: spacing between each tab button
    • sidePadding: horizontal padding applied to the whole tab bar (left & right)
.tabBarLayoutConfig(buttonSpacing: 8, sidePadding: 12)

indicatorStyle

  • Customize Tab underline (indicator) with .tabIndicatorStyle(...).
  • You can set height, color, horizontalInset, cornerRadius, and animationDuration.
.tabIndicatorStyle(
    height: 2,
    color: .blue,
    horizontalInset: 8,
    cornerRadius: 4,
    animationDuration: 0.3
)

isSwipeEnabled

  • Enable or Disable Content Swipe
  • Allow or disable swipe gesture to switch between tabs.
  • Default is true. Use .contentSwipeEnabled(false) to disable swipe navigation.
.contentSwipeEnabled(false) // disables swipe gesture

separatorStyle

  • Adds a separator line between the TabBar and the content area.
  • Use to visually distinguish the tab bar from page content.
.tabBarSeparator(
    color: .gray.opacity(0.2),
    height: 1,
    horizontalPadding: 0,
    isHidden: false
)
Separator ON Separator OFF

πŸ’₯ Installation

SPM

In Xcode, go to File > Add Packages

https://github.com/camosss/TabPagerX.git

CocoaPods

Add to your Podfile

pod 'TabPagerX'

Run

pod install

πŸ’₯ License

TabPagerX is released under an MIT license. See License for more information.

About

Effortless SwiftUI tab pager with dynamic customization

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published