Open-source project
buh/CompactSlider avatar
buh/CompactSlider

CompactSlider: a SwiftUI slider that handles ranges, grids and polar points

CompactSlider is a SwiftUI control for macOS, iOS, watchOS and visionOS.

564 stars43 forksSwiftMIT

At a glance

What is it?
CompactSlider is a SwiftUI control that replaces the built-in Slider and covers more ground: single values, ranges, multiple values, points in a grid and polar points in a circular grid, with horizontal, vertical and scrollable orientations plus a styling API for your own look. It runs on macOS, iOS, watchOS and visionOS.
Who is it for?
CompactSlider suits an app that needs something the built-in SwiftUI Slider cannot express, which in practice means a range handle, a 2D grid, a colour wheel or a fine-adjust control, and the API is small enough that adopting one of those styles costs one modifier.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 88 days ago.
What is it written in?
Mainly Swift, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Why someone rewrote the built-in Slider

The README gives the motive directly, and it is specific rather than aesthetic. The author wrote the component because the built-in slider was very slow under macOS 12 and below, for example when you need to resize the screen with multiple sliders or when animating, and because the design at that time was severely outdated. That is a narrow complaint about old macOS, which raises the obvious question of why the control still exists, and the answer is in the feature surface rather than in the performance story.

The design inspiration is named too. The author was inspired by the slider design in Apple's Photos app, which makes heavy use of sliders, and by the new sliders in the Camera app on iPhone 16 Pro. The result is a control whose look is closer to Apple's own media apps than to the default system slider, which for a photo or video editing interface is the point.

The description calls it a highly customizable multi-purpose slider control for SwiftUI, and the README is clear that it is a replacement for the built-in slider, designed specifically for SwiftUI. The licence is MIT, the primary language is Swift, and the topics list the four platforms the control targets, macOS, iOS, watchOS and visionOS, plus ipados.

Two slider types, and six orientations

The type system is the first thing to understand, because it decides what you can build with the control. The README says the slider basically defines two variants, a linear slider and a grid slider. The linear slider can be horizontal or vertical, and also scrollable, where the handle is still and the scale is moving, which is the opposite of the usual mental model where the track is fixed and the thumb moves.

The grid slider selects a point in a grid or a polar point in a circular grid. A point in the grid represents a value of the x and y axis, and the polar point represents a value of the angle and radius.

These map onto the CompactSliderType values, and the README enumerates them: a horizontal slider with alignments leading, center and trailing, a vertical slider with alignments top, center and bottom, a scrollable horizontal slider, a scrollable vertical slider, a grid slider, and a circular grid slider. Six cases, two underlying mechanisms. The value type you bind decides which half you are in, a Double for the linear case, a CGPoint for the grid case, and a CompactSliderPolarPoint for the circular case.

Binding a value, a range or several values

The basic usage is three lines, and the state wrapper is ordinary SwiftUI:

swift
import CompactSlider

@State private var volume: Double = 0.5

CompactSlider(value: $volume)
    .frame(height: 44)

The frame is worth noting. The control does not impose a height, so you decide how tall it is, and 44 is the value the README uses throughout, which is close to Apple's own minimum touch target. The range variant takes two bindings and a closed range:

swift
import CompactSlider

@State private var minPrice: Double = 20
@State private var maxPrice: Double = 80

CompactSlider(from: $minPrice, to: $maxPrice, in: 0...100)
    .frame(height: 44)

And there is a discrete form with a step, which is the version you want for anything with discrete increments:

swift
import CompactSlider

@State private var brightness: Double = 50

CompactSlider(value: $brightness, in: 0...100, step: 5)
    .frame(height: 44)

The multiple-value form binds an array, which is what you need for a set of markers on a timeline:

swift
import CompactSlider

@State private var markers: [Double] = [0.2, 0.5, 0.8]

CompactSlider(values: $markers)
    .frame(height: 44)

Four initialisers, one shape. The array case is the one with the least obvious behaviour, since the README does not describe how a new marker is added or removed, only that you can bind a set of them.

Switching type with compactSliderStyle

The style modifier is where the orientation and the grid modes are selected, and the default parameter names the case rather than just taking a style:

swift
// Horizontal alignments
CompactSlider(value: $value)
    .compactSliderStyle(default: .horizontal(.leading))  // Default
    .compactSliderStyle(default: .horizontal(.center))
    .compactSliderStyle(default: .horizontal(.trailing))

// Vertical alignments
CompactSlider(value: $value)
    .compactSliderStyle(default: .vertical(.top))
    .compactSliderStyle(default: .vertical(.center))
    .compactSliderStyle(default: .vertical(.bottom))
    .frame(width: 44)

The pattern is that the same initialiser call is reused and the style modifier changes what the value means spatially, so a horizontal leading slider and a vertical top slider are the same control in a different orientation. The scrollable mode flips the moving part:

swift
// Scrollable (fixed handle, moving scale)
CompactSlider(value: $value)
    .compactSliderStyle(default: .scrollable())
    .frame(height: 44)

The grid modes bind different types, which is why they need their own examples:

swift
// Grid (2D point selection)
@State private var point = CGPoint(x: 50, y: 50)

CompactSlider(point: $point, in: .zero...CGPoint(x: 100, y: 100))
    .compactSliderStyle(default: .grid())
    .frame(width: 200, height: 200)

// Circular grid (polar coordinates)
@State private var polarPoint = CompactSliderPolarPoint(angle: .zero, normalizedRadius: 0.5)

CompactSlider(polarPoint: $polarPoint)
    .compactSliderStyle(default: .circularGrid())
    .frame(width: 200, height: 200)

The circular case is the one worth attention, since it uses a normalised radius rather than an absolute one, which means the same control adapts to whatever range you want the radius to cover.

Interaction options: tap, scroll wheel, snapping and fine control

The behaviour options are added rather than substituted, through a modifier with a name that says so:

swift
CompactSlider(value: $value)
    .compactSliderOptionsByAdding(
        .tapToSlide,              // Click to set value
        .scrollWheel,             // macOS scroll wheel support
        .snapToSteps,             // Snap while dragging
        .precisionControl()       // Drag perpendicular for fine control
    )

Each one solves a specific irritation with the built-in control. Tap to slide lets a click jump the value, which matters on macOS where a drag-only slider is awkward with a trackpad. Scroll wheel support lets the scroll wheel adjust the value, which is how native macOS controls behave. Snap to steps aligns the handle to the step grid while dragging. And precision control is the interesting one: dragging perpendicular to the track gives fine adjustment, which is the behaviour a colour or exposure control needs when you are trying to nudge a value without overshooting.

The API being additive matters for a control that replaces an existing one. You add the options you want and the others stay off, so a migration from the built-in Slider does not force you to accept every behaviour change at once.

Scale, handle and the option of not replacing the native look

Customisation is split into three layers. Colours go through the standard SwiftUI accent colour, so no custom API is needed for the common case:

swift
// Colors and styling
CompactSlider(value: $value)
    .accentColor(.purple)
    .frame(height: 44)

The scale is its own modifier with visibility, line length and colour:

swift
// Custom scale
CompactSlider(value: $value)
    .compactSliderScale(
        visibility: .always,
        lineLength: 8,
        color: .blue
    )

And the handle takes a style with a visibility and a radius:

swift
// Custom handle
CompactSlider(value: $value)
    .compactSliderHandleStyle(
        .circle(visibility: .always, radius: 20)
    )

There is also a route to the opposite decision. If you want a native system-styled slider, the library ships SystemSlider alongside CompactSlider:

swift
import CompactSlider

SystemSlider(value: $volume)
SystemSlider(from: $min, to: $max)

So the library offers both the custom control and a system-styled one, which is a practical way to keep a familiar look in some screens while using the richer behaviour in others. The README also documents a default style composition diagram, which is the fastest way to understand how the default style assembles its parts, and full API documentation is hosted on Swift Package Index for CompactSlider, DefaultCompactSliderStyle and SystemSlider separately.

Installing it, and what you need from the toolchain

Installation goes through Swift Package Manager inside Xcode. In Xcode, go to File and then Add Packages, search for the repository URL and click Add Package, then pick the target and confirm:

bash
https://github.com/buh/CompactSlider.git

The requirements are the part to check first, because they set a floor on your project. The README asks for Swift 5.9 or newer, Xcode 16 or newer, SwiftUI 3 or newer, macOS 12 or newer, iOS 15 or newer, watchOS 8 or newer and visionOS 1 or newer. There is one accommodation for older tooling: use the xcode15 branch if you have to use Xcode 15, which is the kind of note that tells you the author supports a lagging audience rather than only the newest.

For a first real use, the smallest thing worth building is a range slider with step snapping and fine control, since those are the behaviours the built-in control lacks. Bind two Doubles, set the step in the initialiser, add the options, and you have a two-handle slider with snapping and perpendicular fine adjustment.

The repository also ships a Demo package containing several use cases, with screenshots for macOS and iOS, and the top-level entries show the rest of the structure: a Sources directory, a Demo directory, ReleaseNotes, a Package.swift, a .spi.yml for Swift Package Index publishing, a Usage.md, a README_v1.md kept for the older major version, a CLAUDE.md and a .github directory.

Where CompactSlider is the wrong choice

Three limits are worth naming. The first is that it is a replacement for a control you already have, and the built-in Slider is fast enough on current systems, so the performance argument that motivated the project was specific to macOS 12 and below and does not carry forward to a modern deployment. If your need is a single continuous value with default appearance, the framework component is the better answer, and the library even ships SystemSlider for when you want that look.

The second is the floor it sets. Swift 5.9, Xcode 16, macOS 12 and iOS 15 are minimums, and they raise the deployment target of any app that adopts it. An app that still supports iOS 14 has to stay on the built-in control, and the README's own answer to that, a branch for Xcode 15, shows that backports exist but are second-class.

The third is that the grid half is a small, unusual piece of API. A CGPoint binding with a closed range, and a CompactSliderPolarPoint with a normalised radius, are not the shapes most SwiftUI code is written against, so the learning curve is real even though the call sites are short. If you need a colour wheel, a gradient editor or a 2D pan control, this is a good fit; if you need a slider, the extra machinery is not free.

On maintenance, the newest release is 2.1.0 from 2025-11-22, after 2.0.9 from 2025-03-26 and 2.0.8 from 2025-03-13, and the last push to the repository was on 2026-07-27, so the tree is being touched between releases. The MIT licence means the code can be vendored into an app without obligations beyond keeping the notice, and the fact that the repository keeps a CLAUDE.md and a Usage.md says the author expects machine-written contributions and a separate usage guide as the primary documentation.

Editorial conclusion

CompactSlider suits an app that needs something the built-in SwiftUI Slider cannot express, which in practice means a range handle, a 2D grid, a colour wheel or a fine-adjust control, and the API is small enough that adopting one of those styles costs one modifier. It is the wrong tool if the native Slider already does what you need, since a third-party control carries its own maintenance and its own SwiftUI version floor, and it is the wrong tool on watchOS where the interaction model barely applies. Verify first which of the two slider types you actually need, the linear one or the grid one, and note that the newest release is 2.1.0 from 2025-11-22 with the last push on 2026-07-27.

Frequently asked questions

What is CompactSlider and what can it do that the built-in SwiftUI Slider cannot?

It is a SwiftUI slider control that replaces the built-in Slider and covers single values, ranges, multiple values, points in a grid and polar points in a circular grid, in horizontal, vertical and scrollable orientations, with options for tap-to-slide, scroll wheel support, step snapping and perpendicular fine control.

How do I add CompactSlider to my Xcode project?

In Xcode go to File, then Add Packages, paste the repository URL https://github.com/buh/CompactSlider.git, click Add Package, then select the target you want it added to and select Add Package.

What are the system requirements for CompactSlider?

Swift 5.9 or newer, Xcode 16 or newer, SwiftUI 3 or newer, macOS 12 or newer, iOS 15 or newer, watchOS 8 or newer and visionOS 1 or newer. The README notes you can use the xcode15 branch if you have to use Xcode 15.

How do I get a range slider with two handles in CompactSlider?

Use the from and to initialiser with a closed range, for example CompactSlider(from: $minPrice, to: $maxPrice, in: 0...100), and bind both values as separate @State properties of type Double.

Can I keep the native system appearance while using CompactSlider?

Yes. The library ships SystemSlider alongside CompactSlider, with initialisers for a single value and for a range, so you can use the system-styled slider where the standard look matters and the custom control where the extra behaviour matters.

What does the scrollable slider type change?

In the scrollable variants the handle stays still and the scale moves, the opposite of the usual arrangement. The CompactSliderType values include a scrollable horizontal slider and a scrollable vertical slider alongside the horizontal and vertical ones with their leading, center, trailing, top and bottom alignments.

Official sources

  1. buh/CompactSlider on GitHub
  2. Issues
  3. License: MIT
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/buh-compactslider.svg)](https://hysenlabs.com/projects/buh-compactslider)

Was this useful?