Recreating Mastodons Audio Player as a Web Component
Tags: webdev, javascript, webcomponents
Published: 2023-12-04 18:19:20

> **TLDR**: I recreated mastodons audio player as a web component, available [reggi/mastodon-audio-player-web-component](https://github.com/reggi/mastodon-audio-player-web-component).

## What was the goal?

The goal was to have a `audio-player` embed like this:

```html
<audio-player src="/file.mp3" poster="/image.jpg"></audio-player>
```

The goal was also to have it look exactly like the `audio-player` that [mastodon uses](https://github.com/mastodon/mastodon/blob/8710bdb183073381250085ffa20e21e22d9069b6/app/javascript/mastodon/features/audio/index.jsx).

![an image of the audio player](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oyzxc5jp1c6291is8cmw.png)

## Why

I was creating a [Astro](https://astro.build/) component `MastodonStatus`, something like:

```ts
<MastodonStatus href="https://indieweb.social/@thomasreggi/111518126442493327"/>
```

And I really wanted to display all the extra post-types, `images`, `poll`, `video`, but when it came to `audio` there was an issue, there was no drop-in player that resembled the mastodon player. Mastodon wrote the original player using React, so it wasn't exactly easy to implement as it was. I really just wanted a `web-component` version to exist for me to drop in and pass the `mp3` and an `image` and be on my way.

Once I started to dive into it and reverse engineer the existing player I started to have hope that it was possible. Everything from the custom volume-slider to figuring out the visualizer was pretty complex. This was also my first time working with the web `Audio` api, which was surprisingly easy to work with.

Making and working with a complex web-component like this wasn't simple but there are some things that helped along the way. 

1. No `template` or `style` tags, I went pure in-js solutions for all dom elements and styles. I think this saved me in the long run. I hate working with long template strings for html and css.
2. Grouping initializable elements in a class method, I would break down every element into a function and attach it to it's parent at the very end, makes it easy to call on elements in other methods.
3. Grouping all event handlers, this made it easy to track all the events within the component.

## What's next?

I'm hoping that other people will find this useful. In an ideal world mastodon also would adopt this component and the community can build on it and make it better. There's some work needed to make sure that the component is accessable, but it was a lot of work to get where I am (I feel like I just lifted a bounder up a mountain). I'm totally open to any pull-requests that address any accessability issues with the component. Let's try and push web-components to be a better standard that are meant to be shared, worked on, and maintained collectivley.

## Project Context

This project was born as a dependency to another project [`astro-cache-embed`](https://github.com/reggi/astro-cache-embed). The projects look something like this, with each being a dependency of the other: [reggi.com](https://github.com/reggi/astro.reggi.com) -> [astro-cache-embed](https://github.com/reggi/astro-cache-embed) -> [mastodon-audio-player-web-component](https://github.com/reggi/mastodon-audio-player-web-component). Here's a [demo of the mastodon-embed](http://reggi.com/demo/mastodon-embed). Here's a demo of the [`mastodon-audio-player-web-component`](https://reggi.github.io/mastodon-audio-player-web-component/).