Skip to content

unionst/union-stacks

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

16 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

UnionStacks

Production-ready SwiftUI layout components for wrapping, flowing, and centering content

Swift 6.0 iOS 16+ SwiftUI License SPM

UnionStacks provides powerful, flexible layout containers that solve common SwiftUI layout challenges. Whether you need tags that wrap like text or perfectly centered navigation bars, UnionStacks makes it effortless.

🎯 Features

  • πŸ“¦ WrappingHStack - Auto-wrapping horizontal layout for tags, chips, and dynamic collections
  • βš–οΈ CStack - Centered layout with balanced distribution for navigation bars
  • πŸš€ Production Ready - Battle-tested in real applications
  • ⚑️ Performant - Efficient layout algorithms optimized for typical UI scenarios
  • πŸ“± Responsive - Adapts automatically to different screen sizes
  • 🎨 Customizable - Flexible spacing and configuration options

πŸ“Έ Quick Examples

WrappingHStack: Flow Layout for Tags

import UnionStacks

struct TagsView: View {
    let tags = ["SwiftUI", "iOS", "Layout", "Custom Views", "Flow"]
    
    var body: some View {
        WrappingHStack(horizontalSpacing: 8, verticalSpacing: 8) {
            ForEach(tags, id: \.self) { tag in
                Text(tag)
                    .padding(.horizontal, 12)
                    .padding(.vertical, 6)
                    .background(Color.blue.opacity(0.2))
                    .clipShape(Capsule())
            }
        }
        .padding()
    }
}

Perfect for:

  • Tag collections (hashtags, categories, keywords)
  • Filter chips and buttons
  • Dynamic content from APIs
  • Any variable-width items that should wrap naturally

CStack: Centered Navigation Bars

import UnionStacks

struct NavBar: View {
    var body: some View {
        CStack(spacing: 16) {
            Button("Back") { }
            Text("Settings").font(.headline)
            Button("Save") { }
        }
        .frame(height: 44)
        .padding(.horizontal)
    }
}

Perfect for:

  • Navigation bars with guaranteed center alignment
  • Toolbars with symmetric left/right actions
  • Any layout where the center item must be perfectly centered

πŸ“¦ Installation

Swift Package Manager

Add UnionStacks to your project using Xcode:

  1. File β†’ Add Package Dependencies
  2. Enter: https://github.com/unionst/union-stacks
  3. Select version and add to your target

Or add to your Package.swift:

dependencies: [
    .package(url: "https://github.com/unionst/union-stacks", from: "1.0.0")
]

πŸš€ Quick Start

1. Import UnionStacks

import SwiftUI
import UnionStacks

2. Use WrappingHStack for flowing content

struct ContentView: View {
    let items = ["Swift", "Kotlin", "Python", "JavaScript", "TypeScript", "Rust"]
    
    var body: some View {
        WrappingHStack(horizontalSpacing: 12, verticalSpacing: 12) {
            ForEach(items, id: \.self) { item in
                Text(item)
                    .padding()
                    .background(Color.blue.opacity(0.2))
                    .clipShape(RoundedRectangle(cornerRadius: 8))
            }
        }
    }
}

3. Use CStack for centered layouts

struct CustomNavBar: View {
    var body: some View {
        CStack {
            Button("Cancel") { dismiss() }
            Text("Title")
            Button("Done") { save() }
        }
    }
}

πŸ“– Documentation

Comprehensive guides and API documentation:

🎨 Real-World Examples

Interactive Filter Chips

struct FilterView: View {
    let filters = ["All", "Active", "Completed", "Archived"]
    @State private var selected = "All"
    
    var body: some View {
        WrappingHStack(horizontalSpacing: 12) {
            ForEach(filters, id: \.self) { filter in
                Button {
                    selected = filter
                } label: {
                    Text(filter)
                        .padding(.horizontal, 16)
                        .padding(.vertical, 8)
                        .background(selected == filter ? Color.blue : Color.gray.opacity(0.2))
                        .foregroundStyle(selected == filter ? .white : .primary)
                        .clipShape(RoundedRectangle(cornerRadius: 8))
                }
                .buttonStyle(.plain)
            }
        }
    }
}

Dynamic Hashtags

struct HashtagView: View {
    @State private var hashtags = ["#swift", "#ios", "#dev"]
    
    var body: some View {
        ScrollView {
            WrappingHStack(horizontalSpacing: 8, verticalSpacing: 8) {
                ForEach(hashtags, id: \.self) { tag in
                    Button {
                        searchHashtag(tag)
                    } label: {
                        Text(tag)
                            .padding(.horizontal, 10)
                            .padding(.vertical, 6)
                            .background(Color.purple.opacity(0.2))
                            .clipShape(Capsule())
                    }
                    .buttonStyle(.plain)
                }
            }
            .padding()
        }
    }
    
    func searchHashtag(_ tag: String) {
        print("Searching: \(tag)")
    }
}

Editable Tags with Remove Buttons

struct EditableTagsView: View {
    @State private var tags = ["SwiftUI", "iOS", "Development"]
    
    var body: some View {
        WrappingHStack(horizontalSpacing: 8, verticalSpacing: 8) {
            ForEach(tags, id: \.self) { tag in
                HStack(spacing: 4) {
                    Text(tag)
                    Button {
                        tags.removeAll { $0 == tag }
                    } label: {
                        Image(systemName: "xmark.circle.fill")
                            .foregroundStyle(.secondary)
                    }
                    .buttonStyle(.plain)
                }
                .padding(.horizontal, 10)
                .padding(.vertical, 6)
                .background(Color.blue.opacity(0.2))
                .clipShape(Capsule())
            }
        }
        .animation(.spring(), value: tags)
    }
}

⚑️ Performance

When to use WrappingHStack

βœ… Excellent performance for:

  • Small to medium collections (1-100 items)
  • Variable-width content (tags, labels)
  • Dynamic content that changes infrequently

⚠️ Consider alternatives for:

  • Very large collections (100+ items) β†’ Use LazyVGrid instead
  • Uniform grid layouts β†’ Use LazyVGrid with fixed columns
  • Infinite scrolling β†’ Use List or LazyVStack

Optimization Tips

WrappingHStack {
    ForEach(items, id: \.id) { item in
        ItemView(item: item)
            .drawingGroup()
    }
}

Use stable identifiers and consider .drawingGroup() for complex child views.

πŸ†š Comparison

WrappingHStack vs HStack vs LazyVGrid

Feature WrappingHStack HStack LazyVGrid
Multiple rows βœ… Automatic ❌ Single row βœ… Grid-based
Wrapping βœ… Natural flow ❌ Truncates βœ… Column-based
Item sizing Ideal size May compress Grid cells
Performance Good (<100 items) Excellent Excellent (lazy)
Best for Tags, chips Fixed layouts Photos, grids
Alignment Left-aligned flow Flexible Vertical columns

When to use each

Use WrappingHStack when:

  • Items have different widths
  • You want natural text-like flow
  • Collection is small to medium
  • Content feels like "tags" or "chips"

Use HStack when:

  • Content always fits in one row
  • You need flexible spacing
  • Building navigation bars or toolbars

Use LazyVGrid when:

  • Items should align in columns
  • You have 100+ items
  • Items are uniform in size
  • You need lazy loading

πŸ›  Requirements

  • iOS 16.0+ / macOS 13.0+ / tvOS 16.0+ / watchOS 9.0+
  • Swift 6.0+
  • Xcode 16.0+

πŸ“„ License

UnionStacks is available under the MIT license. See LICENSE for details.

🀝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.

πŸ”— Related Projects

πŸ“± Apps Using UnionStacks

Is your app using UnionStacks? Open an issue to be featured here!

🌟 Credits

Built with ❀️ by Ben Sage

πŸ” Keywords

SwiftUI, Layout, Custom Layout, Flow Layout, Wrapping Stack, Wrapped HStack, Tag Layout, Chip Layout, iOS Development, Swift Package, SwiftUI Components, Responsive Layout, Dynamic Layout, Auto-wrapping, Horizontal Stack, Centered Layout, Navigation Bar Layout, SwiftUI Layout Protocol, iOS 16, Modern SwiftUI


⭐️ If you find UnionStacks useful, please star the repository!

View Documentation β€’ Report Bug β€’ Request Feature

About

SwiftUI Utility Stacks

Resources

License

Contributing

Stars

Watchers

Forks

Packages

No packages published

Languages