Music Toggle

A play/pause control shaped like a spinning record, with a live waveform and a seekable progress ring.

Open in v0

Last updated: August 13, 2026

Installation

npx smoothui-cli add music-toggle

Features

  • Cover art spins continuously while playing and pauses in place (never resets) when paused
  • Play icon morphs into a pause icon with a spring rotate/scale transition
  • Waveform bars animate scaleY on a deterministic per-bar phase — no Math.random() is used, heights and timing are seeded from the bar index
  • A pathLength-style progress ring around the record doubles as a role="slider" for keyboard seeking
  • Optional src lets the component own an <audio> element; without it, the component is purely visual and the caller drives playing
  • Never autoplays: the underlying <audio> element is only played or paused in response to a playing change made after the initial mount, and its muted property is never touched
  • Respects prefers-reduced-motion

Accessibility

Keyboard Interactions

KeyDescription
Space / EnterToggles play/pause (native <button> behavior)
Arrow Right / Arrow UpSeeks forward, when onSeek is provided
Arrow Left / Arrow DownSeeks backward, when onSeek is provided
Home / EndJumps to the start / end of the track

ARIA Attributes

AttributeElementPurpose
aria-pressedPlay/pause buttonReflects the current playing state
aria-labelPlay/pause buttonReads "Play"/"Pause" plus the track title and artist
role="slider"Progress ringExposes the seek control to assistive technology
aria-valuenow / aria-valuemin / aria-valuemaxProgress ringExposes playback position as a 0–100 percentage
aria-hidden="true"Cover art, waveformHides purely decorative visuals

Screen Reader

  • The play/pause button is a real <button>, so it is announced with its role, pressed state and label out of the box.
  • The waveform bars are aria-hidden; they carry no information not already exposed by the play/pause state.
  • The seek ring is only focusable (tabIndex={0}) when onSeek is supplied — otherwise it is skipped by keyboard navigation.

Reduced Motion

This component respects the prefers-reduced-motion media query via useReducedMotion from Motion. When reduced motion is preferred, the cover art stops rotating, the waveform bars stop animating, and the play/pause icon swaps instantly instead of morphing.

Props

Created by

Powered by

motion.dev

© 2026 SmoothUI. Built by Eduardo Calvo.