Alan's YouTube Player Web Component
Overview
An enhanced YouTube embed experience. It started as a way to clean up the preview thumbnail images and evolved from there.
Usage
- Grab the component file here: youtube-player-v1.js
-
Include it on your page with:
<script type="module" src="/path/to/youtube-player-v1.js" ></script>
-
Use it with the ID from a YouTube video like this:
<youtube-player :video="dQw4w9WgXcQ"><youtube-player>
Features
Video Player
-
Embed videos with a custom
<youtube-player>
element - Basic player controls are always visible
- Built-in aria labels
- Chapter markers (and corresponding chapter skip buttons)
- Fast loading thumbnails
- Custom thumbnails
- Custom titles
- Content advisories
- Stylable controls
- Responsive sizing
- Page level styling
Multiple Players
The component is designed to accommodate multiple video players on a page.
- Starting one video stops other videos on the page
- Playing a video dims the other videos on the page
Page Level Styling
-
A
data-youtube-player-state
attribute is added to the page'sbody
tag when videos are played. It can be used to change the styles on the page. For example, this page fades the background to black and darkens text colors to make videos stand out more
Examples
Default Player
Videos are added via a custom youtube-player
element with a :video
attribute for the ID
of the video to play. For example:
HTML
<youtube-player
:video="LT3cERVRoQo"
><youtube-player>
Output
The component limits what's shown to the thumbnail, title, and player controls. That's compared to the default YouTube embed which puts the play button in the middle of the image. The YouTube player also adds "Watch later", "Share", etc... elements based on how much room is available. Here's an example:
Thumbnails look nicer without the play button covering them. They also load much faster than the default YouTube embed which pulls in the entire player before showing an image.
Full Video URLs
The :video
attribute accepts
full YouTube URLs as well to make them easier to copy/paste:
HTML
<youtube-player
:video="https://www.youtube.com/watch?v=DvJRdS1CaYQ"
><youtube-player>
Output
Chapters
Chapters can be added via the optional :chapters
attribute. Chapter skip buttons slot into
the player controls to move between them:
HTML
<youtube-player
:video="-91vymvIH0c"
:chapters="18, 32, 84, 176, 276, 407, 577"
><youtube-player>
Output
Custom Thumbnails
YouTube thumbnails can be replaced with custom images
HTML
<youtube-player
:video="fiShsfvbFUA"
:thumbnail="/images/rage-against-thumbnail.jpg"
><youtube-player>
Output
Custom Start Time
The component accepts custom start times. For example, this videos doesn't really get going until 54 seconds in:
HTML
<youtube-player
:video="NoMqvniiEkk"
:start="54"
><youtube-player>
Output
Custom End Time
An end time can be set as well. For example, this one only plays the first 11 seconds of the video:
HTML
<youtube-player
:video="REPPgPcw4hk"
:end="11"
><youtube-player>
Output
Custom Title
YouTube titles are used by default. They can be overridden with a custom title. Makes it nice for removing "[Official Video]" type stuff which is what was done for this one:
HTML
<youtube-player
:video="K7xzmkpwNoA"
:title="Little Simz - Gorilla"
><youtube-player>
Output
Content Advisory
The component provides for adding content advisories that can be used for flashing lights, language, sensitive topics, etc...
HTML
<youtube-player
:video="tRwHpyOq4P4"
:advisory="Warning: contains flashing lights"
><youtube-player>
Output
Restarting From The Beginning
Switching between multiple videos on a page stops the one
that was left and returns it to the thumbnail. If you
go back to it, it picks up where it left off by default.
The component also provides a :restart
attribute that sends it back to the beginning instead.
(Note that it doesn't go back just by pausing. You have to
switch to another video to see the behaviour)
HTML
<youtube-player
:video="Cz8cbwR_6ms"
:restart="on"
><youtube-player>
Output
Custom Skip Times
The skip forward and back buttons default to +7sec. and -10sec.
respectively. Those times can be customized with :skip-forward
and :skip-back
attributes.
HTML
<youtube-player
:video="dAwLMS8fgoA"
:skip-forward="3"
:skip-back="3"
><youtube-player>
Output
Details
- Control buttons don't show up until the video player is ready to go
- The highest quality thumbnails are used for videos that have them. They automatically fallback to base quality thumbnails if the higher quality ones don't exist
- Videos can be set to start and end at custom times
- The number of seconds to skip forward and backward can be adjusted
- Videos remember where they are by default. They can also be set to restart from the beginning (of from their custom start time)
- A "Loading" badge overlays the thumbnail while the video is buffering instead of showing a spinner on a black canvas
- When videos end (or another video is played) they revert back to showing only the thumbnail and title
- Clicking directly on a thumbnail doesn't start the video. I set that up originally but it made things harder to use on mobile. It was too easy to play a video instead of scrolling the page when it was the touch target. I don't mind this since the Play button is always visible
- Paused videos continue to show the contents of the YouTube iframe. This allows for jumping to different parts of the video, changing the closed captions, altering the settings, etc...
- When one video is paused and another one is started the first video reverts to just the thumbnail and title to provided a cleaner look and feel
- Videos that are played all the way to the end revert to just the thumbnail and title display
- Videos that are played all the way to the end and are played again will use their custom start time if one was set
- The SVGs for the player control buttons are built into the component's CSS. Check the Styling section below for how to style them.
- Hover state fix in place for mobile devices to prevent them from getting stuck in a hover state
- Flash messages display when moving between chapters or skipping forward and back.
- There's a brief delays in the style changes when the video is paused to accommodate for the player sending a pause signal when scrubbing to a different part of the video. It prevents fading in and out if a new location is clicked on the video timeline. The fade will generally occur if when dragging back and forth on the timeline.
Player Styling
The player includes default styles
for the text, border, and buttons. They can be
adjusted with CSS custom property variables
on the parent page (either globally in something
like :root
or via .class
or #id
selectors).
Text Styling
Text styles are controlled via:
--youtube-player--text-color
--youtube-player--text-background-color
--youtube-player--font-size
They default to:
--youtube-player--text-color: #ccc
--youtube-player--text-background-color: rgb(0 0 0 / 0.3);
--youtube-player--font-size: 0.9rem;
Border Styling
The border can be styled for three different states:
--youtube-player--faded-border
--youtube-player--playing-border
--youtube-player--stopped-border
The defaults are:
--youtube-player--faded-border: 1px solid #222;
--youtube-player--playing--border: 1px solid #aaa;
--youtube-player--stopped--border: 1px solid #999;
Button Color Styling
The colors for the buttons are set with:
--youtube-player--base-button-background
--youtube-player--base-button-foreground
--youtube-player--faded-button-background
--youtube-player--faded-button-foreground
They default to:
--youtube-player--base-button-background: rgb(255 255 255 / 0.4);
--youtube-player--base-button-foreground: rgb(0 0 0 / 0.8);
--youtube-player--faded-button-background: rgb(255 255 255 / 0.2);
--youtube-player--faded-button-foreground: rgb(0 0 0 / 0.3);
Hovering over a button causes the foreground and background to reverse.
Button Icons
The buttons use SVGs for their icons. The varialbes are:
--youtube-player--fast-forward-icon
--youtube-player--mute-icon
--youtube-player--next-chapter-icon
--youtube-player--pause-icon
--youtube-player--play-icon
--youtube-player--previous-chapter-icon
--youtube-player--restart-icon
--youtube-player--rewind-icon
--youtube-player--unmute-icon
They can be updated with an embedded URL for another SVG. For example:
--youtube-player--play-icon: url("data:image/svg+xml;utf8,%3Csvg%0A%20%20viewBox%3D%220%200%20100%20100%22%0A%20%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%0A%20%20stroke%3D%22red%22%0A%20%20fill%3D%22grey%22%3E%0A%20%20%3Ccircle%20cx%3D%2250%22%20cy%3D%2250%22%20r%3D%2240%22%20%2F%3E%0A%3C%2Fsvg%3E%0A");
The buttons use
mask-image
for
the SVGs. That allows them to be styled with
the custom CSS property variables. The masking is
done as an alpha channel. Colors aren't used.
Note that you'll need to properly escape the SVG string for things to work. See: Optimizing SVGs in data URIs for guidance.
Transition Time
The transition time for the fades can be updated with:
--youtube-player--transition-time
It defaults to:
--youtube-player--transition-time: 0.3s
Page Styling
The player adds a data-youtube-player-state
attribute to the <body>
tag
of the page the first time a video is played.
The value is playing
whenever a
video is playing. This attribute can be used to
adjust styles on the page outside the player's
custom element.
For example, this page has the following styles which fade the background to black and the text colors to gray via my custom CSS properties when the video is playing:
body {
transition: background-color 0.6s ease-in, color 0.6s ease-in;
}
body[data-youtube-player-state="playing"] {
--background-color: black;
--primary-color: #444;
--secondary-color: #444;
}
Known Bugs
- There's a dead area in the middle of the thumbnails that doesn't scroll on iOS (and possibly other mobiles)
- The 'Play' button doesn't switch to the 'Pause' display if the video is started by pressing the chapter skip button
Someday/Maybe TODOs
-
Add better error handling for videos
that don't exist or if the
:video
attribute is missing - Write up how to use the default YouTube embed for progressive enhancement
- Add button sizes to global vars
- Show the length of the video
- Make an error message if there's no video id available
- Figure out if a video won't play in a certain region and provide a fallback
- Preload videos on network connections that can handle it
- Add a short delay (e.g. 300ms) before showing the loading badge so it doesn't show up if the video starts quickly.
- Add ability to float the video player keeping it in frame when scrolling. Or, maybe a button to drop it down into the side of the page
- Add a volume slider
- Add fade-in, fade-out for volume
Notes
- Need to get a better understanding of how focusing is working with keyboard events
- This version of the component doesn't attempt to auto-play the video. Might look at that via an optional attribute in the future
- I experimented with adding buttons to change the playback speed. It cluttered things up more that I liked. Might play with that again in the future.
- I thought about adding the ability to set a custom ratio that would zoom the player in to avoid black bars. That won't work directly since the zoom could potentially make the iframe controls inaccessible
- I'd like to be able to add a closed caption on/off button. It doesn't look like that's possible with the ifram API though