Skip to content

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

Playback Speed Button Group for Svelte

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

UI library: Ark UI

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 Svelte, Ark UI does not change how fast media plays.

Preview

Preview width

Installation

MCP · Pro
Make your AI a shadcn expert
Your agent installs components, builds pages and restyles your app from one prompt, in Claude Code, Cursor or VS Code.
Part of Pro

Anatomy

Button Group anatomy: root, group, button, separator

Usage

<div class="flex flex-col gap-4"><ButtonGroup aria-label="Playback speed">{#each SPEEDS as item (item)}<Button aria-pressed={speed === item} onclick={handleSelect} size="sm" value={String(item)} variant={speed === item ? "default" : "outline"}>{item}x</Button>{/each}</ButtonGroup><ButtonGroup aria-label="Playback speed preset">{#each PRESETS as item (item.label)}<Button aria-pressed={speed === item.value} onclick={handleSelect} size="sm" value={String(item.value)} variant={speed === item.value ? "default" : "outline"}>{item.label}</Button>{/each}</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.