Skip to content

Develop

A circular play / pause control. The button’s outline acts as the visible ring; drop a <div class="tng-media-button-progress"> inside to overlay a 360° progress arc on top.

<button class="tng-media-button" aria-label="Play">
<i class="tng-icon icon-player" aria-hidden="true"></i>
</button>

The progress ring carries role="progressbar" plus aria-valuemin / aria-valuemax / aria-valuenow for screen readers, and the --tng-media-button-progress custom property (a number between 0 and 1) drives the visual fill. Keep aria-valuenow (0–100) and the custom property (0–1) updated together so visuals and announcements stay in sync.

<button class="tng-media-button" aria-label="Play">
<div
class="tng-media-button-progress"
role="progressbar"
aria-valuemin="0"
aria-valuemax="100"
aria-valuenow="0"
style="--tng-media-button-progress: 0"
></div>
<i class="tng-icon icon-player" aria-hidden="true"></i>
</button>
<button class="tng-media-button" aria-label="Pause">
<div
class="tng-media-button-progress"
role="progressbar"
aria-valuemin="0"
aria-valuemax="100"
aria-valuenow="42"
style="--tng-media-button-progress: 0.42"
></div>
<i class="tng-icon icon-ui-pause" aria-hidden="true"></i>
</button>
<button class="tng-media-button" aria-label="Replay">
<div
class="tng-media-button-progress"
role="progressbar"
aria-valuemin="0"
aria-valuemax="100"
aria-valuenow="100"
style="--tng-media-button-progress: 1"
></div>
<i class="tng-icon icon-player" aria-hidden="true"></i>
</button>

The default size is lg (64 × 64). Use is-sm for the compact 40 × 40 variant — typically secondary controls in a player toolbar.

<button class="tng-media-button is-sm" aria-label="Play">
<i class="tng-icon icon-player" aria-hidden="true"></i>
</button>
<button class="tng-media-button is-lg" aria-label="Play">
<i class="tng-icon icon-player" aria-hidden="true"></i>
</button>

Disabled is expressed via the native disabled attribute. Hover, active and focus states are driven by the browser and styled by the design system — no extra classes needed.

<button class="tng-media-button" aria-label="Play">
<i class="tng-icon icon-player" aria-hidden="true"></i>
</button>
<button class="tng-media-button" disabled aria-label="Play">
<i class="tng-icon icon-player" aria-hidden="true"></i>
</button>

Wires the media button to a <video> element. The toggle flips between play and pause icons, the aria-label and aria-pressed track the playback state, and --tng-media-button-progress is updated from a requestAnimationFrame loop scoped to playback so the ring traces playback time.

Press play to see the progress ring trace playback time.

source code

The same wiring works for any source — <audio>, custom playback engines, HLS streams. The contract is “set the number on the progress element”; everything else is decoupled.