A web component for playing videos with suport for YouTube, Vimeo and self-hosted video.
npm install @morton-studio/video-player Web ComponentA fully customizable and responsive Web Component that supports:
- YouTube videos (including Shorts)
- Vimeo videos
- Self-hosted videos (MP4, WebM, etc.)
- Poster images in AVIF, WebP, JPG, PNG
- Optional fullscreen, custom play button, and auto-sizing
The home page for this project is at https://github.com/johnfmorton/video-player where you will find the source code.
You can view a working demo of this component at https://johnfmorton.github.io/video-player/.
This web-component was built because I needed a video player that could handle YouTube, Vimeo, and self-hosted videos. The project required being able to have custom poster frames which would load the video player upon click.
I also wanted a self-contained component with a simple API that would allow me to easily add videos to my projects without having to worry about the underlying implementation details.
This is the result.
---
#### npm
The video-player component is available via npm at https://www.npmjs.com/package/@morton-studio/video-player.
Install it with npm:
``sh`
npm install @morton-studio/video-player
Next, import and register the component in your JavaScript file. Note that you can register the component with a custom tag name when using npm.
`js
import { registerVideoPlayer } from '@morton-studio/video-player'
registerVideoPlayer()
// If you want to customize the tag name, pass in a string:
// registerVideoPlayer('my-video-player')
`
If you prefer not to use npm, you can include the component directly in your HTML file. This will load the latest version from a CDN and register the component automatically.
#### jsDelivr
`html`
#### unpkg
`html`
If you are using the CDN version, you don't need to do anything else. The component will be registered automatically using the default tag name in your HTML.
Then use it in your HTML:
`html`
You may include the YouTube and Vimeo APIs in your HTML file if you want to use their features directly in other parts of your application.
This is optional, as the component will automatically load them if needed by looking on the Window object for YT or Vimeo. If either API is not required, the component will not load them. For example, if you have no Vimeo URLs in video-player components on your page, the Vimeo API will not be loaded.
`html`
Automatically determines video type based on the src URL:
- YouTube URLs (incl. Shorts): https://www.youtube.com/watch?v=..., https://youtu.be/..., https://youtube.com/shorts/...https://vimeo.com/...
- Vimeo:
- Self-hosted: anything else (assumes direct video file)
Supports predefined aspect ratios:
- 16x9 (default)4x3
- 1x1
- 9x16
-
Use the aspect-ratio attribute:
`html`
Use a single image:
`html`
Or use multiple formats:
`html`
Use the posteralt attribute to improve accessibility:
`html`
Adds a centered play icon on the poster frame:
`html`
Use the allowfullscreen attribute:
`html`
The
* video-playvideo-pause
* video-ended
*
Each event is dispatched with a detail object containing the following properties:
- type: The type of video service (e.g., youtube, vimeo, self-hosted).src
- : The source URL of the video.currentTime
- : The current playback time in seconds, if available.duration
- : The total duration of the video in seconds, if available.
This allows developers to handle events consistently, regardless of the underlying video player technology.
Make the component stretch to fill its container:
`html`
This is useful inside flex or grid layouts.
---
You can customize the appearance of the play button using CSS variables:
`css`
video-player {
--play-button-bg: rgba(0, 0, 0, 0.7); / Button background /
--play-button-arrow: white; / Triangle color /
--play-button-bg-hover: rgba(0, 0, 0, 0.9); / Background on hover /
}
These variables let you customize the style without modifying the component directly.
---
This component has built-in accessibility features:
- Poster images have customizable alt text.Enter
- All clickable elements (poster, play button) are keyboard accessible via and Space keys.role="button"
- The poster is focusable and labeled with and aria-label.
- Uses semantic
---
Use the sources attribute (as a JSON string):
`html`
---
`html`
posters='{
"webp": "/images/poster.webp",
"png": "/images/poster.png"
}'
posteralt="Preview frame for YouTube video"
playbutton
allowfullscreen
aspect-ratio="16x9">
`html`
{ "src": "/video.mp4", "type": "video/mp4" },
{ "src": "/video.webm", "type": "video/webm" }
]'
posters='{
"avif": "/images/poster.avif",
"jpg": "/images/poster.jpg"
}'
posteralt="Preview frame for self-hosted video"
playbutton
allowfullscreen
autosize
aspect-ratio="9x16">
---
Include the JS file via
`
Or import and register manually:
`js`
import VideoPlayer, { registerVideoPlayer } from './video-player.js';
registerVideoPlayer();
You can also customize the tag name:
`js``
registerVideoPlayer('my-video-player');
---
- Written in plain TypeScript but compiles to ES6 for compatibility.
- Uses Shadow DOM
- No external dependencies
- Easily extensible for subtitles, controls, etc.
---
All notable changes to this project will be documented in the CHANGELOG.md file.
---
---