Docs
Inputs

Scrub Stepper

A glass stepper you tap, hold to repeat or scrub sideways across, with buttons that melt into the pill at a bound.

$npx swiftpieces add ScrubStepper
See it in a Pro app On a real screen in one of the Pro apps: open it with Pro, take it apart, remix it, and copy the SwiftUI.
Free · MIT + Commons ClauseiOS 17.0+Liquid Glassstepperscrubdraghapticnumeric
Type
ScrubStepper
Files
ScrubStepper.swift
Depends on
Nothing (Apple frameworks only)
Version
2.2.0
In a full screen · SwiftPieces ProStayA stay detail screen over full-bleed scenery, with a floating booking card that rises and flicks away.

Liquid glass minus/plus stepper with hold-to-repeat and a horizontal scrub gesture. The three parts rest joined, so liquid necks hold them together. At a bound the button that can no longer act melts into the numeral pill, and it buds back out of the pill as soon as the value can move that way again. The buttons keep their place in the layout while they are away, so the stepper never changes width.

Notes

  • One DragGesture(minimumDistance: 0) covers the whole capsule and decides by start location: the round buttons at each end press, the numeral block in the middle starts a scrub. A press that moves more than 14pt sideways becomes a scrub; one that leaves the capsule by more than 20pt cancels without stepping.
  • Pressed buttons invert (glyph color fills the circle) and sink to 0.86 on a quick spring with no overshoot, then spring back with a little give when you let go; a button at its bound dims. A tap bounces its glyph; a hold or a scrub steps too fast for a bounce to read, so they don't.
  • Hold-to-repeat starts after 400ms and accelerates from 100ms to 60ms after 1.5s and 30ms after 3s. It runs in a Task that is cancelled on release, on cancel (including a touch the system takes over), on disappear, and when a bound is hit.
  • Scrubbing consumes one step per 14pt of travel, multiplied by a velocity gain of up to 4x. The value stops when your finger does; nothing coasts. While scrubbing, the block lifts (slightly larger, on a soft shadow) and a ruler fades in a beat later and runs with the finger, faster on a flick. The lift is visual only, so the capsule's layout never changes under the finger.
  • Digits roll on a tap, a VoiceOver step or a change from your code, landing without overshoot. While a hold repeats or a scrub steps they change in place, so they stay readable.
  • Every step ticks a .selection haptic, throttled to one per 35ms during fast repeats and scrubs. A scrub step that lands on the bound and hits the stop in the same moment fires only the stop's impact.
  • At a bound, a tap, a repeat tick or a VoiceOver step fires a rigid impact and knocks the block 4pt toward that end and back. A scrub that keeps pushing pulls the block against that end with rubber-band resistance, about 4pt at most, while the ruler stops and the value stays at the bound; the impact fires once each time it reaches the stop, and on release the block springs back at the speed it was moving. The stop holds back no more than 14pt of travel however far you push, so coming back the block relaxes within those 14pt and the value steps one step's travel later.
  • Style sets the trough, buttons, glyph, the numeral block and its ink, and the height (44pt minimum, 52pt by default). .standard uses the butter block; pass .init(block:) for another.
  • Supply an .accessibilityLabel; the value and adjustable action are provided.
  • Reduce Motion: no press scale, no lift scale, no glyph bounce and no block movement at a bound. The buttons still invert, the lifted block keeps its shadow, the ruler still runs, digits cross-fade instead of rolling, a bound darkens the block for a beat instead of moving it, and every haptic stays.

Usage

ScrubStepperExample()

Parameters

ParameterDescription
valueBound integer value.
rangeAllowed values. Pushing past a bound fires a rigid impact and knocks the numeral pill against that end; a scrub pulls it there with rubber-band resistance.
stepAmount added or removed per tap, repeat tick, or scrub unit.
styleTints and size. Defaults to the SwiftPieces house palette (signal buttons around a neutral glass pill), adapting to light and dark.

Install

Pick one. Run it from the folder that contains your .xcodeproj and the files land inside your app.

Terminal

$npx swiftpieces add ScrubStepper

Or ask your coding agent · Claude Code, Cursor or Xcode, once the MCP server is connected

>Add the SwiftPieces "Scrub Stepper" piece to my app

Or copy the source above into your app.

New to SwiftUI?If you know React, CSS or Tailwind, SwiftUI is easier to pick up than it looks.Try real app patterns first

Building a whole app? See SwiftPieces Pro →

All inputs and forms →

Build it yourself: SwiftUI haptics guide

On this page

SwiftPiecesPro

Build the whole app with one library.

Production-ready screens, whole flows, complete app templates, a Build Kit your agent follows and Pro remixing.

54 screens · 46 patterns · 48 flows · 12 templates · 31 Build Kit skills

Explore Pro