Skip to content

Repository files navigation

Kaizōsha’s CustomKit

CustomKit is a focused collection of native-feeling SwiftUI controls for iOS and iPadOS. Its first control is Slider, a tactile capsule slider for choosing from a finite set of values.

Developed by Kaizōsha and created by Kaizō Konpaku.

CustomKit works entirely on device. It has no network behavior, analytics, persistence, external assets, or third-party package dependencies.

Requirements

  • Swift 6.4
  • Xcode 27 or newer
  • iOS 27 or iPadOS 27

CustomKit does not support macOS, Mac Catalyst, tvOS, watchOS, or visionOS.

Installation

In Xcode, choose File > Add Package Dependencies and enter:

https://github.com/Kaizosha/CustomKit.git

Select version 0.2.0 or newer, then add the CustomKit library to the app target.

For a Swift package, add:

dependencies: [
    .package(
        url: "https://github.com/Kaizosha/CustomKit.git",
        from: "0.2.0"
    )
]

Then add .product(name: "CustomKit", package: "CustomKit") to the consuming target.

Minimal Use

import CustomKit
import SwiftUI

struct PlaybackSpeedControl: View {
    @State private var value = 1.0

    var body: some View {
        CustomKit.Slider(
            value: $value,
            stops: [0.5, 1, 1.25, 1.5, 2],
            accessibilityLabel: "Playback speed",
            accessibilityValue: { "\($0.formatted())×" }
        )
        .padding()
        .background(.black, in: .rect(cornerRadius: 20))
    }
}

SwiftUI also provides a control named Slider. CustomKit’s control is CustomKit.Slider; use SwiftUI.Slider when you mean the system continuous slider. The module-qualified spelling keeps both controls clear when an app imports both frameworks.

The original white appearance is designed for a dark media surface, as shown above. On a normal system background, use semantic colors through SliderStyle; the customization example below is a ready-made starting point for light and dark appearances.

Slider filters invalid values, removes duplicates, and sorts its stops. Each remaining stop receives equal visual spacing: [0, 1, 10] places 1 in the center rather than one tenth of the way across the rail. The control displays the nearest stop, and a user adjustment writes that stop to the binding.

Selection is drag-only. A tap does not jump the value. Moving vertically away from the rail enables finer horizontal adjustment, while crossing a stop provides selection feedback.

Customization

Pass a SliderStyle with style: to customize the rail, fill, stop dots, thumb, dimensions, shadow, animation, and feedback while preserving the same interaction behavior. The default keeps lower values on the left, matching the original design. Pass .automatic or .rightToLeft through direction: when the host should mirror or explicitly reverse the mapping.

Only name the values that should differ from the default:

let sliderStyle = CustomKit.SliderStyle(
    trackColor: .secondary.opacity(0.24),
    fillColor: .mint,
    knobColor: .mint,
    restingRailHeight: 36,
    activeRailHeight: 44
)

The accessibility label describes the setting, and the accessibility value closure describes the selected value. Supply localized text from the host app:

CustomKit.Slider(
    value: $value,
    stops: availableValues,
    style: sliderStyle,
    direction: CustomKit.SliderDirection.automatic,
    accessibilityLabel: String(localized: "Intensity"),
    accessibilityValue: { value in
        value.formatted(.percent)
    },
    onEditingChanged: { isEditing in
        interactionIsActive = isEditing
    }
)

VoiceOver exposes a control with multiple stops as adjustable and moves one stop at a time. A one-stop fallback is announced as a static value. onEditingChanged reports true after a drag becomes active and false when the interaction ends or is cancelled. Programmatic binding updates do not start an editing session.

Behavior and Limitations

  • The control is horizontal and UIKit-backed, with a SwiftUI public API.
  • Stops are discrete, sorted, and equally spaced; continuous ranges are not supported.
  • Provide at least one finite stop. Invalid and duplicate stops do not create positions; if none remain, the current bound value becomes the sole fallback stop.
  • Dragging changes the selection; tapping the rail intentionally does not.
  • The host owns value meaning, formatting, localization, and persistence.
  • Custom styles should retain a comfortable touch target and sufficient contrast in every system appearance.
  • CustomKit does not render labels for individual stops. Place explanatory content next to the slider when the values are not self-evident.

Validation

Before shipping a customized slider:

  1. Build the host app with Xcode 27 for iPhone and iPad.
  2. Exercise every stop in left-to-right and right-to-left layouts.
  3. Verify VoiceOver increment, decrement, label, and value announcements.
  4. Check light and dark appearance, Increased Contrast, Reduce Transparency, and Reduce Motion.
  5. Test touch cancellation, compact layouts, rotation, Split View, and Stage Manager.
  6. Run the package tests and the host app’s focused UI tests.

Because CustomKit imports UIKit, validate it with an iOS or iPadOS destination rather than treating a macOS command-line build as platform coverage.

Documentation

Open the package documentation in Xcode for the complete Slider behavior and customization contract.

License

CustomKit is available under the MIT License.

About

Kaizōsha’s native SwiftUI controls for iOS and iPadOS, created by Kaizō Konpaku.

Topics

Resources

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages