Library / SDK
danielsaidi/ScrollKit avatar
danielsaidi/ScrollKit

ScrollKit: stretchy, sticky headers and offset tracking for SwiftUI

Powerful SwiftUI scroll capabilities.

870 stars36 forksSwiftMIT

At a glance

What is it?
ScrollKit is a SwiftUI library that wraps ScrollView to add two things the stock scroll view does not give you: a live offset and a header that stretches on pull down and sticks to the top. It installs with Swift Package Manager and targets every major Apple platform.
Who is it for?
ScrollKit is worth adopting for teams that ship iPhone and iPad apps with a collapsing hero header, a floating toolbar or any layout that reacts to scroll position, since the offset plumbing arrives as two ready made views instead of a private geometry preference setup.
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 140 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 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The scroll features SwiftUI leaves out of the box

ScrollView in SwiftUI gives you a scrolling container and a content closure. It does not tell you where the content currently sits, and it has no concept of a header that reacts to the gesture. That gap shows up the moment a designer asks for a large title that shrinks as the user scrolls, or a banner that stretches when the list is pulled down.

The usual way to build that yourself in SwiftUI is to place a background view behind the scroll content, read its frame through a GeometryReader, and shuttle the coordinates into the header with a preference key. It works, and it is also code you now own and must debug on every OS release.

ScrollKit exists to remove that step. The README describes it as a SwiftUI library that adds scroll features such as offset tracking and a header view that stretches and transforms as you pull down, then sticks to the top when you scroll. The audience is app developers who already decided they want one of those two behaviours and would rather not hand roll it.

Two wrapper views instead of a rewritten ScrollView

The library exposes the behaviour through two SwiftUI views rather than through modifiers, and each one wraps the scroll view for you.

ScrollViewWithOffsetTracking is the smaller half. It reports the scroll offset through a closure and, according to the README, can detect scrolling on all OS versions.

ScrollViewWithStickyHeader is the larger half. It takes a header view plus a set of parameters that describe how the header should behave: a resting height, a minimum height, an optional stretch toggle, an optional corner radius mask on the content, and an optional scroll handler action. The handler receives both the offset and the visible header ratio, which is the number you need if the header should fade or scale as it collapses.

The architectural choice is worth noticing. ScrollKit does not use the new ScrollView APIs, and the README is explicit about why: backwards compatibility. The author says the library will eventually move to them. Until that happens, the implementation is built on the older approach, which is what makes the wide OS support possible.

For layout, the header example uses a ZStack with a colour, the built in ScrollViewHeaderGradient, and a text view reading the current offset. The gradient is what gives the header its dark backdrop without any custom drawing.

Installing ScrollKit with Swift Package Manager

ScrollKit is distributed as a Swift package. The README gives the package URL, and the usual route is to add it to a project through the package manager in Xcode, or to declare it in a Package.swift dependency.

bash
https://github.com/danielsaidi/ScrollKit.git

The repository root carries a Package.swift file, a Sources directory, a Tests directory and a Demo directory, which is the layout of a standard library package. The demo is a separate Xcode project rather than an executable target, and the README says the way to try the library out is to open and run the Demo project.

The README also points to an online documentation site with a getting started guide, articles and code examples. That is where the fuller API reference lives; the README itself covers the entry points and the main parameters, and leaves the rest to the documentation site.

Reading the scroll offset with ScrollViewWithOffsetTracking

The simplest use of the library is the offset tracking view. You pass a closure that receives the current offset, and your scroll content goes in the content closure.

swift
ScrollViewWithOffsetTracking { offset in
    print(offset)
} content: {
    // Add your scroll content here, e.g. a `LazyVStack`
}

The README states that this view can detect scrolling on all OS versions, which matters because it is the piece you drop into an existing screen to make a bar fade, a title shrink, or a button appear once the user passes a threshold. The closure fires as the scroll changes, so reading the value in the body is how you drive that state.

One design consequence follows from the callback shape: the offset arrives as a closure parameter rather than as a published property, so the calling view decides what to store. If your app needs the offset in several places, you are the one who has to put it somewhere shared, for example in a state property on the parent view.

Configuring the sticky header and its collapse behaviour

The sticky header view takes the parameters that decide how the header reacts, and the README example wires each one with an inline comment so the intent is visible.

swift
        ScrollViewWithStickyHeader(
            header: stickyHeader,   // A header view
            headerHeight: 250,      // The resting header height
            headerMinHeight: 150,   // The minimum header height
            headerStretch: false,   // Disables the stretch effect
            contentCornerRadius: 20, // An optional corner radius mask
            onScroll: handleScroll  // An optional scroll handler action
        ) {
            // Add your scroll content here, e.g. a `LazyVStack`
        }

Two parameters carry most of the visual weight. headerHeight is the resting height, so 250 points is the full height of the banner before any scrolling happens, and headerMinHeight is where it settles, 150 points in the example. headerStretch toggles the pull down effect, and the example sets it to false, which turns that off.

The scroll handler is where a proportional value arrives:

swift
    func handleScroll(_ offset: CGPoint, visibleHeaderRatio: CGFloat) {
        self.scrollOffset = offset
        self.visibleRatio = visibleHeaderRatio
    }

The visible header ratio lets the header fade or shrink in step with its own visible area instead of with raw scroll pixels, which is usually what a designer means by a proportional header. contentCornerRadius is a separate cosmetic detail that masks the content with a rounded corner.

What the wrapper approach costs, and where to draw the line

ScrollKit is a wrapper, and wrappers have a cost. Because it does not use the new ScrollView APIs, the library is pinned to the older mechanism until the author migrates it. Any new scroll capability the platform adds will not appear in ScrollKit on the day it ships, and when the migration does happen, the behaviour of existing screens can shift.

There is also a level of magic in the header parameters. The README documents what headerHeight, headerMinHeight and headerStretch do, but it does not publish the exact interpolation curve between the two heights, so a designer asking for a specific easing may need to adjust it in the app rather than in the library.

For the alternative, the honest comparison is with writing the geometry plumbing yourself. A local implementation using a GeometryReader and a coordinate space preference gives full control over every interpolated value and avoids the dependency, at the cost of code in your codebase and the same preference mechanism the library already solves. ScrollKit is the choice when that code would otherwise be copied into several screens, and the local approach is the choice when the header behaviour is unusual enough that you would fight the parameters anyway.

The repository states the licence is MIT, and the README asks sponsors to fund the work. The last push was on 2026-06-05, and the most recent release is 0.9.0 from 2025-10-23, with earlier tags 0.8.1 and 0.8.0 in 2025.

Editorial conclusion

ScrollKit is worth adopting for teams that ship iPhone and iPad apps with a collapsing hero header, a floating toolbar or any layout that reacts to scroll position, since the offset plumbing arrives as two ready made views instead of a private geometry preference setup. It is the wrong dependency when your app targets only recent OS versions and you would rather use the current system scroll APIs directly, and the wrong choice for projects that cannot take on an MIT licensed third party package. Verify first that the header behaviour you need is covered by the headerHeight, headerMinHeight and headerStretch parameters, then build the Demo project in Xcode and confirm the sticky behaviour on the oldest iOS version you ship to.

Frequently asked questions

How do I install ScrollKit in a SwiftUI project?

Add it with Swift Package Manager using the package URL https://github.com/danielsaidi/ScrollKit.git, then import ScrollKit in the files that use it.

Does ScrollKit work on older iOS versions?

The README states that ScrollViewWithOffsetTracking can detect scrolling on all OS versions and that the library works on all major Apple platforms, which is why it avoids the new ScrollView APIs for backwards compatibility.

How do I make the header stretch when pulling down?

The stretch effect is part of ScrollViewWithStickyHeader and can be disabled with the headerStretch parameter, so leaving it unset keeps the effect on.

Can I get the visible portion of the header while scrolling?

Yes. The onScroll handler receives the offset and a visibleHeaderRatio value, and the README example stores it in a state property named visibleRatio.

Official sources

  1. danielsaidi/ScrollKit on GitHub
  2. License: MIT
  3. Project website
  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/danielsaidi-scrollkit.svg)](https://hysenlabs.com/projects/danielsaidi-scrollkit)

Was this useful?