Skip to main content

You can bind to properties of <audio> and <video> elements, making it easy to (for example) build custom player UI, like AudioPlayer.svelte.

First, add the <audio> element along with its bindings (we’ll use the shorthand form for src, duration and paused):

AudioPlayer
<div class="player" class:paused>
	<audio
		{src}
		bind:currentTime={time}
		bind:duration
		bind:paused
	></audio>

	<button
		class="play"
		aria-label={paused ? 'play' : 'pause'}
	></button>

Next, add an event handler to the <button> that toggles paused:

AudioPlayer
<button
	class="play"
	aria-label={paused ? 'play' : 'pause'}
	onclick={() => paused = !paused}
></button>

Our audio player now has basic functionality. Let’s add the ability to seek to a specific part of a track by dragging the slider. Inside the slider’s pointerdown handler there’s a seek function, where we can update time:

AudioPlayer
function seek(e) {
	const { left, width } = div.getBoundingClientRect();

	let p = (e.clientX - left) / width;
	if (p < 0) p = 0;
	if (p > 1) p = 1;

	time = p * duration;
}

When the track ends, be kind — rewind:

AudioPlayer
<audio
	{src}
	bind:currentTime={time}
	bind:duration
	bind:paused
	onended={() => {
		time = 0;
	}}
></audio>

The complete set of bindings for <audio> and <video> is as follows — seven readonly bindings...

  • duration — the total duration, in seconds
  • buffered — an array of {start, end} objects
  • seekable — ditto
  • played — ditto
  • seeking — boolean
  • ended — boolean
  • readyState — number between (and including) 0 and 4

...and five two-way bindings:

  • currentTime — the current position of the playhead, in seconds
  • playbackRate — speed up or slow down (1 is ‘normal’)
  • paused — this one should be self-explanatory
  • volume — a value between 0 and 1
  • muted — a boolean value where true is muted

Videos additionally have readonly videoWidth and videoHeight bindings.

Edit this page on GitHub

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<script>
	import AudioPlayer from './AudioPlayer.svelte';
	import { tracks } from './tracks.js';
</script>
 
<div class="centered">
	{#each tracks as track}
		<AudioPlayer {...track} />
	{/each}
</div>
 
<style>
	.centered {
		display: flex;
		flex-direction: column;
		height: 100%;
		justify-content: center;
		gap: 0.5em;
		max-width: 40em;
		margin: 0 auto;
	}
</style>