ESC

Start typing to search...

Getting Started

Introduction

Beta

KaxhyapUI is an open-source SwiftUI toolkit that fills gaps in SwiftUI by providing components, extensions, and utilities that complement the standard library and make development faster and more enjoyable.

Early versions focus on practical UI components and helpers. Future releases will also introduce Liquid Glass inspired UI built for Apple's evolving design direction.

Beta: KaxhyapUI is currently in beta. APIs are not frozen and may change before v1.0.0.

Features

  • SwiftUI components that streamline common UI needs
  • Reusable, modular view building blocks
  • Practical API utilities and extensions
  • Built using modern system APIs without legacy compatibility
  • Distributed via Swift Package Manager
Getting Started

Who is KaxhyapUI for?

KaxhyapUI is designed for developers who embrace modern SwiftUI development.

SwiftUI Developers

Building apps for iOS 17+ and macOS 15+

Productivity Seekers

Looking to streamline common UI patterns

Teams

Want clean, reusable UI components

Modern API Lovers

Prefer SwiftUI-only APIs

Note: KaxhyapUI may not be suitable if you need support for older OS versions (pre-iOS 17, pre-macOS 15) or UIKit-based components.

Getting Started

Design Philosophy

KaxhyapUI follows a set of core principles that guide every component we build.

1

Fill the Gaps

Focus on components and utilities that complement SwiftUI's standard library, addressing common needs that aren't covered out of the box.

2

Modern System APIs

Built using modern system APIs without legacy compatibility. No support for older OS versions as of now.

3

Minimal APIs

Public APIs are kept small, focused, and purposeful. Prefer composition over configuration.

4

SwiftUI Only

Public-facing APIs are pure SwiftUI. UIKit is used internally only when required by the system.

5

Quality Over Quantity

KaxhyapUI prioritizes fewer, well-designed components instead of a large collection of shallow ones. Avoid unnecessary abstractions.

Getting Started

Platform Support

KaxhyapUI is built for modern Apple platforms.

iOS 17+

Full support for iPhone and iPad

Supported

macOS 15+

Native Mac app support

Supported

Coming Soon: tvOS, visionOS, and watchOS support will be added in a future stable release.

No support for older OS versions as of now. This is intentional to ensure we can use the latest APIs without compromise.

Getting Started

Installation

KaxhyapUI is distributed using Swift Package Manager.

Adding the Package

Follow these steps to add KaxhyapUI to your Xcode project:

1

Open your Xcode project

2

Go to File → Add Package Dependency

3

Enter the repository URL:

Repository URL
https://github.com/sachinkaxhyap/KaxhyapUI
4

Choose the version rule "Up to Next Major" starting from version 0.1.0

Importing the Library

Once added, import KaxhyapUI in your SwiftUI files:

Swift
import KaxhyapUI
Getting Started

Library Status

Beta

KaxhyapUI is currently in active development

This means:

  • APIs are not frozen
  • Breaking changes may occur between releases
  • Feedback and suggestions are welcome
  • The library is actively developed

API stability will be introduced starting with version 1.0.0.

Components

Components Overview

KaxhyapUI is built as a collection of independent, reusable SwiftUI components.

Each component:

Solves a specific UI problem Can be used independently Has minimal setup Follows modern SwiftUI patterns

Available Components

More components are planned for future releases. Check the Roadmap for upcoming additions.

Components

AsyncStateView

New in 0.2.0

A view that displays different content based on the current async state—handling loading, success, error, and empty states in a consistent way.

AsyncStateView eliminates boilerplate code when working with asynchronous data loading patterns, providing sensible defaults while remaining fully customizable.

Platform Requirements

iOS 17.0+ macOS 14.0+ tvOS 17.0+ watchOS 10.0+

AsyncState Enum

The component is powered by the AsyncState enum which represents the state of an asynchronous operation:

Swift
public enum AsyncState<T> {
    case idle
    case loading
    case success(T)
    case failure(Error)
    case empty
}

idle

Initial state before any action

loading

Operation in progress

success(T)

Data loaded successfully

failure(Error)

Operation failed with error

empty

No data available

Helper Properties

The AsyncState enum provides convenient computed properties:

Swift
state.isLoading  // Bool - true if loading
state.data       // T? - the success value if present
state.error      // Error? - the error if failed

Basic Usage

Create an AsyncStateView by providing a state and a content builder for the success case:

Swift
import KaxhyapUI

struct ContentView: View {
    @State private var state: AsyncState<[Item]> = .idle
    
    var body: some View {
        AsyncStateView(state: state) { items in
            List(items) { item in
                Text(item.name)
            }
        }
    }
}

Adding Retry Functionality

Provide a retry closure to enable retry buttons on the error state:

Swift
AsyncStateView(state: viewModel.state) { data in
    List(data) { item in
        Text(item.name)
    }
} retry: {
    viewModel.load()
}

The retry button uses system styling for a clean, native appearance across all supported platforms.

Customizing Empty State

Use the .emptyState() modifier to customize the empty state appearance:

Swift
AsyncStateView(state: state) { items in
    List(items) { item in
        ItemRow(item: item)
    }
}
.emptyState(
    title: "No Items",
    systemImage: "folder",
    description: "Add your first item to get started"
)

Customizing Error State

Use the .errorState() modifier to customize the error state appearance:

Swift
AsyncStateView(state: state) { data in
    DataView(data: data)
} retry: {
    viewModel.refresh()
}
.errorState(
    title: "Connection Failed",
    systemImage: "wifi.slash"
)

Complete Example

Here's a full example showing AsyncStateView integrated with a ViewModel:

Swift
import SwiftUI
import KaxhyapUI

@Observable
class ItemsViewModel {
    var state: AsyncState<[Item]> = .idle
    
    func load() async {
        state = .loading
        do {
            let items = try await fetchItems()
            state = items.isEmpty ? .empty : .success(items)
        } catch {
            state = .failure(error)
        }
    }
}

struct ItemsView: View {
    @State private var viewModel = ItemsViewModel()
    
    var body: some View {
        NavigationStack {
            AsyncStateView(state: viewModel.state) { items in
                List(items) { item in
                    Text(item.name)
                }
            } retry: {
                Task { await viewModel.load() }
            }
            .emptyState(
                title: "No Items",
                systemImage: "folder",
                description: "Your items will appear here"
            )
            .navigationTitle("Items")
        }
        .task {
            await viewModel.load()
        }
    }
}

Default Values

AsyncStateView provides sensible defaults that you can override:

Property Default Value
emptyTitle "No Data"
emptySystemImage "tray"
emptyDescription "There's nothing to display"
errorTitle "Something Went Wrong"
errorSystemImage "exclamationmark.triangle"

Best Practices

Use .empty state when data loads successfully but is empty
Always provide a retry closure for recoverable errors
Customize empty state messages to be context-specific
Use appropriate SF Symbols for your specific use case
Avoid using .idle for extended periods—transition to loading or another state quickly
Components

WebView

The WebView component provides a simple way to display web content in SwiftUI applications.

It supports two presentation styles:

  • An embedded web view using the system web rendering engine
  • A system Safari-based view for external web content

Common Use Cases

Legal or privacy pages
External links inside apps
Web-based dashboards
Help documentation

Basic Usage

To display a web page inside your SwiftUI view, create a WebViewK instance and provide a valid URL:

Swift
import KaxhyapUI

struct ContentView: View {
    var body: some View {
        WebViewK(url: URL(string: "https://example.com"))
    }
}

You can place WebViewK inside any SwiftUI layout such as a VStack, NavigationStack, or TabView.

Presentation Styles

WebViewK supports two presentation styles:

Embedded Web View

Renders the web content directly inside your SwiftUI view hierarchy. Useful when the web content is part of the app's flow.

WebViewK(url: url, style: .embedded)

Safari View

Presents content using the system Safari interface. Useful for external links, authentication pages, or content that should feel separate.

WebViewK(url: url, style: .safari)

Handling Invalid URLs

If WebViewK is created without a valid URL, it automatically shows a system "content unavailable" view. This prevents crashes and provides a clear user-facing message.

Best Practices

Always validate or safely unwrap URLs before passing them
Use Safari style for external or third-party content
Use embedded web view style for internal content
Avoid overloading the component with navigation or business logic

Limitations

WebViewK focuses on simplicity and common use cases. Advanced customization such as:

  • JavaScript message handling
  • Custom navigation controls
  • Deep web-to-native communication

These features may be added in future versions but are intentionally out of scope for the initial beta release.

Components

Toast

New in 0.4.0

A lightweight toast notification that slides in from the bottom of the screen, with support for clear and prominent visual styles, optional action buttons, and auto-dismiss.

Toast is applied as a SwiftUI view modifier using .toast(). It automatically adapts to the platform — using glass effects on iOS 26+ and material backgrounds on earlier versions.

Platform Requirements

iOS 17.0+ macOS 14.0+

Preview

ToastStyle Enum

The visual appearance of the toast is controlled by the ToastStyle enum:

Swift
public enum ToastStyle {
    case clear
    case prominent(Color)
}

Clear

.toast(message: "Copied", isPresented: $show, style: .clear)

Prominent

.toast(message: "Saved", isPresented: $show, style: .prominent(.blue))

Basic Usage

Apply the .toast() modifier to any view to present a toast notification from the bottom:

Swift
import KaxhyapUI

struct ContentView: View {
    @State private var showToast = false
    
    var body: some View {
        VStack {
            Button("Copy") {
                showToast = true
            }
        }
        .frame(maxHeight: .infinity)
        .toast(
            message: "Copied to clipboard",
            isPresented: $showToast,
            systemImage: "checkmark.circle"
        )
    }
}

Adding an Action Button

Provide an actionTitle and an action closure to display a tappable button inside the toast:

Swift
.toast(
    message: "Item deleted",
    isPresented: $showToast,
    systemImage: "trash",
    style: .prominent(.red),
    actionTitle: "Undo"
) {
    viewModel.undoDelete()
}

Tapping the action button automatically dismisses the toast after executing the closure.

Using a Custom Asset Image

Instead of an SF Symbol, you can use a custom image asset from your asset catalog:

Swift
.toast(
    message: "Achievement unlocked!",
    isPresented: $showToast,
    image: "trophy-icon",
    style: .prominent(.orange)
)

Complete Example

Here's a full example showing multiple toast styles in a single view:

Swift
import SwiftUI
import KaxhyapUI

struct ToastDemoView: View {
    @State private var showClear = false
    @State private var showClearAction = false
    @State private var showProminent = false
    @State private var showProminentAction = false
    
    var body: some View {
        VStack(spacing: 16) {
            Button("Clear") {
                showClear = true
            }
            
            Button("Clear + Action") {
                showClearAction = true
            }
            
            Button("Prominent") {
                showProminent = true
            }
            
            Button("Prominent + Action") {
                showProminentAction = true
            }
        }
        .toast(
            message: "Copied to clipboard",
            isPresented: $showClear,
            systemImage: "checkmark.circle",
            style: .clear
        )
        .toast(
            message: "Copied to clipboard",
            isPresented: $showClearAction,
            systemImage: "checkmark.circle",
            style: .clear,
            actionTitle: "Undo"
        ) {
            showClearAction = false
        }
        .toast(
            message: "Saved successfully",
            isPresented: $showProminent,
            systemImage: "checkmark.circle",
            style: .prominent(.blue)
        )
        .toast(
            message: "Saved successfully",
            isPresented: $showProminentAction,
            systemImage: "arrow.uturn.backward",
            style: .prominent(.blue),
            actionTitle: "Undo"
        ) {
            showProminentAction = false
        }
    }
}

Parameters

Parameter Type Default Description
message String The text to display in the toast.
isPresented Binding<Bool> Controls the visibility of the toast.
systemImage String? nil An SF Symbol name displayed alongside the message.
image String A custom asset image name (uses the asset image overload).
style ToastStyle .clear The visual style — .clear or .prominent(Color).
duration TimeInterval 2.0 Seconds before auto-dismiss. Set to 0 to disable.
actionTitle String? nil Title for an optional action button in the toast.
action (() -> Void)? nil Closure executed when the action button is tapped.

Platform Adaptation

Toast automatically adapts its rendering based on the OS version:

iOS 26+ / macOS 26+

Uses the new .glassEffect() API for a native Liquid Glass appearance. Action buttons use .buttonStyle(.glass).

iOS 17 & 18 / macOS 14 & 15

Falls back to .ultraThinMaterial for the clear style and solid color backgrounds for prominent. Action buttons use .buttonStyle(.bordered).

Best Practices

Keep toast messages short and informative
Use .prominent for important or success/error notifications
Provide an action button for reversible operations (e.g., Undo)
Use a meaningful SF Symbol to reinforce the message context
Avoid using toast for critical information that requires user acknowledgment — use an alert instead

Note: The toast uses a spring animation (duration: 0.4, bounce: 0.2) for its entrance and exit transitions. It slides in from the bottom combined with an opacity fade.

Extensions

Image Compressor

New in 0.3.0

Compress images to fit within a specified maximum file size using an intelligent binary search algorithm.

The Image Compressor extension provides a simple API to compress UIImage (iOS) and NSImage (macOS) instances to a target file size in kilobytes. It automatically handles quality adjustment and progressive resizing when needed.

Platform Requirements

iOS 17.0+ macOS 15.0+

Common Use Cases

Upload size limits
Email attachments
Storage optimization
API payload limits

Basic Usage

Compress an image to fit within a maximum file size:

Swift — iOS
import KaxhyapUI

let originalImage: UIImage = // ... from camera, picker, etc.

// Compress to maximum 500 KB
if let compressedData = originalImage.compressedTo(maxSizeKB: 500) {
    // Upload compressedData to server or save locally
}
Swift — macOS
import KaxhyapUI

let originalImage: NSImage = // ... from file, pasteboard, etc.

// Compress to maximum 500 KB
if let compressedData = originalImage.compressedTo(maxSizeKB: 500) {
    // Upload compressedData to server or save locally
}

Async Usage

For large images, use the async version to avoid blocking the main thread:

Swift
// Compress asynchronously
let compressedData = await originalImage.compressedTo(maxSizeKB: 500)

// Or use in a Task
Task {
    if let data = await image.compressedTo(maxSizeKB: 200) {
        await uploadImage(data)
    }
}

The async version runs the compression on a background thread with .userInitiated priority, keeping your UI responsive.

How It Works

The compressor uses a multi-step approach to achieve the target file size:

1

Dimension Check

First, the image is constrained to a maximum dimension of 4096 pixels to prevent memory issues with very large images.

2

Quality Optimization

A binary search algorithm finds the optimal JPEG compression quality (between 0.1 and 0.95) that produces an image close to but not exceeding the target size.

3

Progressive Resizing

If compression alone can't reach the target, the image is progressively resized until it fits within the size limit.

Complete Example

Here's a full example showing image compression in a photo upload flow:

Swift
import SwiftUI
import PhotosUI
import KaxhyapUI

struct PhotoUploadView: View {
    @State private var selectedItem: PhotosPickerItem?
    @State private var isCompressing = false
    @State private var uploadStatus: String?
    
    var body: some View {
        VStack(spacing: 20) {
            PhotosPicker(selection: $selectedItem, matching: .images) {
                Label("Select Photo", systemImage: "photo")
            }
            
            if isCompressing {
                ProgressView("Compressing...")
            }
            
            if let status = uploadStatus {
                Text(status)
                    .foregroundStyle(.secondary)
            }
        }
        .onChange(of: selectedItem) { _, newItem in
            Task {
                await processImage(newItem)
            }
        }
    }
    
    private func processImage(_ item: PhotosPickerItem?) async {
        guard let item,
              let data = try? await item.loadTransferable(type: Data.self),
              let image = UIImage(data: data) else {
            return
        }
        
        isCompressing = true
        
        // Compress to max 500 KB for upload
        if let compressedData = await image.compressedTo(maxSizeKB: 500) {
            let originalKB = data.count / 1024
            let compressedKB = compressedData.count / 1024
            uploadStatus = "Compressed: \(originalKB) KB → \(compressedKB) KB"
            
            // Upload compressedData...
        } else {
            uploadStatus = "Compression failed"
        }
        
        isCompressing = false
    }
}

Parameters

Parameter Type Description
maxSizeKB Int Maximum file size in kilobytes. Must be greater than 0.

Return Value

Returns Data? containing the compressed JPEG image data, or nil if:

  • The maxSizeKB parameter is 0 or negative
  • The image cannot be converted to JPEG format
  • Compression fails for any other reason

Best Practices

Use the async version for images from camera or photo library
Show a progress indicator during compression
Handle the nil return case gracefully
Choose a reasonable target size (100-1000 KB for most use cases)
Avoid extremely small target sizes (under 50 KB) as quality may suffer significantly

Note: The output format is always JPEG. If you need PNG or other formats, additional processing may be required.

Resources

API Stability Policy

Before version 1.0.0

  • APIs may change
  • Renaming and refactoring may occur
  • New parameters or behaviors may be introduced

After version 1.0.0

  • Public APIs will remain stable
  • Breaking changes will follow semantic versioning
  • Deprecations will be communicated clearly
Resources

Roadmap

Planned future work for KaxhyapUI includes:

Liquid Glass components
Buttons, toolbars, and tab UI
Bottom sheet and reusable screen templates
Loading and skeleton state utilities
Async helpers
Text fields and form components
Navigation/layout helpers

Stability and API guarantees will come with v1.0.0. The roadmap may evolve based on platform changes and community feedback.

Resources

Contributing

We welcome discussions, issues, and contributions.

When contributing, please follow these guidelines:

Keep APIs small, focused, and purposeful

Focus on intentional, well-designed interfaces

Prefer composition over configuration

Build modular, composable components

Avoid unnecessary abstractions

Keep code simple and direct

Follow modern SwiftUI patterns

Use idiomatic SwiftUI and system conventions

Discussion, feedback, and suggestions are encouraged.

Resources

License

MIT License

KaxhyapUI is released under the MIT License.

This allows free use, modification, and distribution in both personal and commercial projects.

Resources

Support & Feedback

If you find KaxhyapUI useful, here's how you can help:

Community input helps shape the future of the library.