Step player

An iOS-style stepped progress track with a play, pause and replay control. The active step stretches into a bar that fills as it plays.

Dependencies

motionflubber

Interaction Type

Press play to start the sequence. The current step stretches into a bar and fills as it runs, then shrinks to a filled dot when it hands off to the next one. Press again to pause mid-fill; the play icon splits into the pause bars as it goes. At the end it fades into a replay arrow. Steps can be clicked to jump.

Props

Options you can pass to customize this component.

Prop
Type
Description
steps
numberStepPlayerStep[]

How many steps to show. Pass an array to give each one its own duration or label.

value
number

Active step index, for controlled use. Leave it out and the component tracks its own index.

defaultValue
number

Step to start on when uncontrolled. Clamped to the last step.

onValueChange
(value: number) => void

Fires when the step advances, wraps, or is clicked. Also fires on replay.

playing
boolean

Play state, for controlled use. Leave it out to let the button drive it.

defaultPlaying
boolean

Whether the sequence starts running on mount when uncontrolled.

onPlayingChange
(playing: boolean) => void

Fires when the button is pressed, and when the last step ends without loop.

duration
number

Milliseconds each step runs for. A per-step duration overrides it; 0 stops the timer so you can drive the index yourself.

loop
boolean

Wraps back to the first step instead of stopping. The replay button never appears when this is on.

onComplete
() => void

Fires when the last step finishes, on every pass when looping.

size
number

Height of the track and button in pixels. Every other dimension is a fixed ratio of it, so the dots, bar, gaps, padding, icon, and tap targets all scale from this one number.

showControl
boolean

Shows the round play button. Turn it off for a track on its own and drive it with the playing prop.

controlPosition
leftright

Which side of the track the button sits on.

speeds
number[]

Speeds the time label cycles through when pressed. Pass a single speed to pin it and turn the label back into plain text.

onSpeedChange
(speed: number) => void

Called with the new speed each time the label is pressed.

seekable
boolean

Lets a step be clicked to jump to it. The dots keep a finger-sized tap target at every size.

className
string

Extra classes merged onto the root element. It sizes itself from the size prop, so give it a width only if you want the track wider than its content.

Installation

npx shadcn@latest add swamimalode07/rare-ui/step-player

How to use

import { StepPlayer } from "@/components/ui/step-player"
export function Demo() {
return <StepPlayer steps={5} duration={3000} />
}
// drive your own carousel off the index
<StepPlayer
steps={slides.length}
value={index}
onValueChange={setIndex}
loop
/>

Source Code

Click the code icon in the top-right corner to view the source code.

Keep in mind

Most components here are recreations of great work from around the web. I don't claim to be the original creator - this is my attempt to reverse-engineer, replicate, and often add a few extra features. I've tried to credit everyone; if I missed someone, let me know.

Contact

Found a bug or issue? Feel free to drop a DM.

License & Usage

  • •MIT with the Commons Clause and an attribution requirement. Free to use, modify and ship in personal and commercial projects, closed source included. You own the code once it is in your project.
  • •Credit is required. Any project shipping a Rare UI component must credit Rare UI with a visible link back to rareui.com, in a footer, an about page, a credits screen or a README.
  • •Don't strip the credit or the copyright notice from the source you copied.
  • •Don't sell, sublicense or redistribute the components themselves, on their own, bundled into a template, kit, theme or paid course, or ported to another framework.
  • •Don't republish them. No mirrors, no re-uploads, no listing them as your own work.
  • •Don't repackage the registry as a competing component library.
  • •Don't claim authorship of a component or of Rare UI itself.
  • •The LICENSE file in the repository is the full text and governs. Ask first if your use doesn't fit these rules.
Step player

Step 1 of 5