Skip to content

shadcn.io is an independent project built on shadcn/ui

Playback Speed Button Group for React

Playback rates from 0.5x to 2x, and Slow, Normal, Fast, and Faster, sharing a speed that starts at 1x.

One speed, two rows, starting at 1. Rates are 0.5x, 0.75x, 1x, 1.25x, 1.5x, and 2x. Presets are Slow, Normal, Fast, and Faster, mapped to 0.5x, 1x, 1.5x, and 2x. Normal and 1x both start filled. Choosing Fast also fills 1.5x.

Use the rates for a precise player and the names when a word is enough. If six rates do not fit, a Select takes less width. In React, Base UI does not change how fast media plays.

Preview

Preview width

Installation

Sign in to get your install command
Free with an account. It carries your token, so the CLI installs everything in one go.

Anatomy

Button Group anatomy: root, group, button, separator

Usage

<div className="flex flex-col gap-4">
  <ButtonGroup aria-label="Playback speed">
    {SPEEDS.map((item) => (
      <Button
        aria-pressed={speed === item}
        key={item}
        onClick={handleSelect}
        size="sm"
        value={String(item)}
        variant={speed === item ? "default" : "outline"}
      >
        {item}x
      </Button>
    ))}
  </ButtonGroup>
  <ButtonGroup aria-label="Playback speed preset">
    {PRESETS.map((item) => (
      <Button
        aria-pressed={speed === item.value}
        key={item.label}
        onClick={handleSelect}
        size="sm"
        value={String(item.value)}
        variant={speed === item.value ? "default" : "outline"}
      >
        {item.label}
      </Button>
    ))}
  </ButtonGroup>
</div>

FAQ

How is the speed stored?

As a number, starting at 1. Each button carries its rate as its value, and pressing it stores that rate as a number.

Why does Fast light up 1.5x too?

The presets map to rates: Slow is 0.5, Normal 1, Fast 1.5 and Faster 2. Both rows compare against the same number, so the matching buttons fill together. 0.75x and 1.25x have no preset.

How is the selected rate shown?

Its button uses variant="default" and sets aria-pressed. The others use outline.

How do I apply the speed to a player?

Set the media element's playbackRate to the stored number when it changes. The demo has no player.

How is 1.25x written?

The label is the number followed by x. Format it yourself if you want a different style, such as 1.25×.

What if six buttons don't fit?

Keep the preset row, or move the rates into a Select or a menu.

API Reference

Button Group

Sets aria-label="Playback speed" and aria-label="Playback speed preset". The rest is on the Button Group page.

Button

Sets aria-pressed={speed === item}, onClick={handleSelect}, size="sm", value={String(item)}, variant={speed === item ? "default" : "outline"} and aria-pressed={speed === item.value}. The rest is on the Button page.