Skip to content

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

Player Controls Button Group for Solid

Previous, play or pause, and next, as icons and as labels, sharing a playing flag that starts paused.

UI library: Ark UI

Transport controls, starting paused. The middle button swaps between play and pause, and both rows read that same flag. The icon row names each button. The labeled row says Previous, Play, and Next. Previous and Next do nothing.

Use this under audio or video, and connect the flag to the media yourself. A fine volume level is a Slider. In Solid, Ark UI does not play or pause the media.

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="Player controls">
        <Button aria-label="Previous" size="icon-sm" variant="outline">
          <SkipBackIcon aria-hidden="true" />
        </Button>
        <Button aria-label={isPlaying() ? "Pause" : "Play"} onClick={togglePlaying} size="icon-sm" variant="outline">
          {isPlaying() ? <PauseIcon aria-hidden="true" /> : <PlayIcon aria-hidden="true" />}
        </Button>
        <Button aria-label="Next" size="icon-sm" variant="outline">
          <SkipForwardIcon aria-hidden="true" />
        </Button>
      </ButtonGroup>
      <ButtonGroup aria-label="Player controls">
        <Button size="sm" variant="outline">
          <SkipBackIcon aria-hidden="true" data-icon="inline-start" />
          Previous
        </Button>
        <Button onClick={togglePlaying} size="sm" variant="outline">
          {isPlaying() ? <PauseIcon aria-hidden="true" data-icon="inline-start" /> : <PlayIcon aria-hidden="true" data-icon="inline-start" />}
          {isPlaying() ? "Pause" : "Play"}
        </Button>
        <Button size="sm" variant="outline">
          Next
          <SkipForwardIcon aria-hidden="true" data-icon="inline-end" />
        </Button>
      </ButtonGroup>
    </div>

FAQ

How does play switch to pause?

A playing flag starts as false. The middle button flips it, and shows PauseIcon with Pause while playing or PlayIcon with Play otherwise.

How are the icon-only controls named?

Each has an aria-label: Previous, Next, and Play or Pause from the flag. They use size="icon-sm", and the icons have aria-hidden="true".

Do both rows control the same player?

Yes. Both middle buttons flip the same flag, so they always agree.

Do Previous and Next do anything?

No. They have no handler. Wire them to your playlist or to seek the media element.

How do I connect this to audio or video?

Call play() or pause() on the media element when the flag changes, and update the flag from its play and pause events so the button follows the real state.

Why is the Next icon after the label?

It points forward, so it follows the text with data-icon="inline-end". Previous puts its icon first.

API Reference

Button Group

Sets aria-label="Player controls". The rest is on the Button Group page.

Button

Sets aria-label="Previous", size="icon-sm", variant="outline", aria-label={isPlaying() ? "Pause" : "Play"}, onClick={togglePlaying} and aria-label="Next". The rest is on the Button page.