# Step Player

> A React stories progress bar: an iOS-style stepped track with a play, pause and replay button, whose active step fills as it plays.

- Type: React component (Media)
- Access: Free (the source is open to everyone)
- Version: 1.0.1
- Install: `npx wingo-ui@latest add step-player`
- Docs: https://wingo-ui.com/components/step-player

## Interaction

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. With seekable on, tap any step to jump to it and keep playing; the dots keep a finger-sized tap target and a visible focus ring for keyboard users.

## Installation

```bash
npx wingo-ui@latest add step-player
```

The CLI adds the files, their dependencies and a version record for updates.

With shadcn: `npx shadcn@latest add https://wingo-ui.com/r/step-player.json`

Files:

- `components/ui/step-player.tsx`

npm dependencies: `npm i flubber motion && npm i -D @types/flubber`

Wingo UI dependencies (installed automatically):

- [UIProvider](https://wingo-ui.com/components/ui-config) ([Markdown](https://wingo-ui.com/components/ui-config.md))

## Usage

```tsx
"use client"

import { useState } from "react"
import { StepPlayer } from "@/components/ui/step-player"

export function Demo() {
  return <StepPlayer steps={5} duration={3000} />
}

// drive your own carousel off the index
const slides = ["Welcome", "Invite your team", "Ship it"]

export function Carousel() {
  const [index, setIndex] = useState(0)

  return (
    <div className="grid gap-4">
      <p className="text-lg font-medium">{slides[index]}</p>
      <StepPlayer steps={slides.length} value={index} onValueChange={setIndex} loop />
    </div>
  )
}
```

## Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `steps?` | `number \| StepPlayerStep[]` | `4` | How many steps to show. Pass an array of { duration?, label? } to give each one its own duration or accessible label. |
| `size?` | `number` | `48` | Height of the track and button in pixels (minimum 12). 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. |
| `controlPosition?` | `"left" \| "right"` | `"right"` | Which side of the track the button sits on. |
| `showControl?` | `boolean` | `true` | Shows the round play button. Turn it off for a track on its own and drive it with the playing prop. |
| `trackColor?` | `string` | `""` | Any CSS color for the pill track and the round control. Empty uses #F4F4F9 light, #262626 dark. |
| `fillColor?` | `string` | `""` | Any CSS color for finished steps and the running fill. Empty uses #3C3C43 light, #EBEBF5 dark. |
| `pendingColor?` | `string` | `""` | Any CSS color for the steps still to come. |
| `iconColor?` | `string` | `""` | Any CSS color for the play, pause and replay glyph and the focus outline. Empty uses #868593. |
| `duration?` | `number` | `4000` | Milliseconds each step runs for. A per-step duration overrides it; 0 stops the timer so you can drive the index yourself. |
| `loop?` | `boolean` | `false` | Wraps back to the first step instead of stopping. The replay button never appears when this is on. |
| `seekable?` | `boolean` | `false` | Lets a step be clicked to jump to it (and starts playing from there). The dots keep a finger-sized tap target at every size. |
| `playLabel?` | `string` | `"Play"` | Accessible name of the control while paused. |
| `pauseLabel?` | `string` | `"Pause"` | Accessible name of the control while playing. |
| `replayLabel?` | `string` | `"Replay"` | Accessible name of the control after the last step. |
| `positionLabel?` | `string` | `"Step {index} of {count}"` | Accessible name of the track; {index} and {count} fill in. |
| `stepLabel?` | `string` | `"Step {index}"` | Accessible name of each seek target when seekable and a step has no label; {index} fills in. |
| `defaultValue?` | `number` | `0` | Step to start on when uncontrolled. Clamped to the last step. |
| `defaultPlaying?` | `boolean` | `false` | Whether the sequence starts running on mount when uncontrolled. |
| `value?` | `number` |  | Active step index, for controlled use. Leave it out and the component tracks its own index. |
| `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. |
| `onPlayingChange?` | `(playing: boolean) => void` |  | Fires when the button is pressed, when a step is clicked, and when the last step ends without loop. |
| `onComplete?` | `() => void` |  | Fires when the last step finishes, on every pass when looping. |
| `className?` | `string` |  | Extra classes merged onto the root element (data-slot="step-player"). It sizes itself from the size prop, so give it a width only if you want the track wider than its content. Other div props are spread onto it too. |

## Parts

### StepPlayerStep (type)

One entry of steps when it is an array: { duration?, label? }. duration (ms) overrides the player's for that step, label names its seek target.

## Examples

- **Onboarding stories**: Controlled with value and onValueChange, so the slide follows the player; seekable lets a tap jump to any step.
- **Steps with their own length**: An array of steps sets each duration and names each seek target; loop starts over at the end.
- **Over a photo**: Light track, fill and icon colors with the control on the left, like a story viewer.

## See also

- [Steps](https://wingo-ui.com/components/steps) ([Markdown](https://wingo-ui.com/components/steps.md))
- [Progress](https://wingo-ui.com/components/progress) ([Markdown](https://wingo-ui.com/components/progress.md))
- [Onboarding Carousel](https://wingo-ui.com/components/onboarding-carousel) ([Markdown](https://wingo-ui.com/components/onboarding-carousel.md))
- [Carousel](https://wingo-ui.com/components/carousel) ([Markdown](https://wingo-ui.com/components/carousel.md))
- [Video Player](https://wingo-ui.com/components/video-player) ([Markdown](https://wingo-ui.com/components/video-player.md))

---

Canonical: https://wingo-ui.com/components/step-player
More components: https://wingo-ui.com/components · Index for agents: https://wingo-ui.com/llms.txt
