{"id":14990336,"url":"https://github.com/gyanreyer/hover-video-player","last_synced_at":"2025-09-01T06:33:17.992Z","repository":{"id":62755861,"uuid":"493880003","full_name":"Gyanreyer/hover-video-player","owner":"Gyanreyer","description":"A web component for rendering videos that play on hover, including support for mouse and touch events and a simple API for adding thumbnails and loading states.","archived":false,"fork":false,"pushed_at":"2024-07-18T14:34:04.000Z","size":2338,"stargazers_count":30,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-08-08T11:30:57.614Z","etag":null,"topics":["custom-element","hover","video","video-playback","web-component"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Gyanreyer.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-05-19T01:30:01.000Z","updated_at":"2025-05-12T22:29:09.000Z","dependencies_parsed_at":"2024-09-24T16:01:42.550Z","dependency_job_id":null,"html_url":"https://github.com/Gyanreyer/hover-video-player","commit_stats":{"total_commits":44,"total_committers":1,"mean_commits":44.0,"dds":0.0,"last_synced_commit":"cc9caaa86dcbc8207321d80a43f472ce9ab79ffb"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/Gyanreyer/hover-video-player","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Gyanreyer%2Fhover-video-player","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Gyanreyer%2Fhover-video-player/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Gyanreyer%2Fhover-video-player/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Gyanreyer%2Fhover-video-player/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Gyanreyer","download_url":"https://codeload.github.com/Gyanreyer/hover-video-player/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Gyanreyer%2Fhover-video-player/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":273082416,"owners_count":25042282,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-01T02:00:09.058Z","response_time":120,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["custom-element","hover","video","video-playback","web-component"],"created_at":"2024-09-24T14:19:54.652Z","updated_at":"2025-09-01T06:33:17.907Z","avatar_url":"https://github.com/Gyanreyer.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# hover-video-player\n\nA web component that helps make it easy to set up videos which play when the user hovers over them.\n\nThis is particularly useful for the common user experience pattern where a page may have a thumbnail which plays a video preview when the user hovers over it.\n\nThis is a port of the [react-hover-video-player library](https://github.com/Gyanreyer/react-hover-video-player) which should be broadly compatible with Svelte, Vue, vanilla HTML, or any other library/framework which supports web components!\n\n**[Play with a real working example on CodeSandbox.](https://codesandbox.io/s/hover-video-player-example-pcw27m?file=/index.html)**\n\n## Features\n\n- Support for mouse, touchscreen, and keyboard focus interactions\n- Built-in support for thumbnails and loading states\n- Adds handling for weird edge cases that can arise when managing video playback, such as gracefully falling back to playing the video without sound if the browser's autoplay policy blocks un-muted playback\n- Supports HTMLMediaElement API-compliant custom elements, allowing for use of other media sources like YouTube, Vimeo, and HLS\n\n## Installation\n\n### package managers\n\n- `npm install hover-video-player`\n- `yarn add hover-video-player`\n\n### cdn\n\n- esm build (recommended): `\u003cscript type=\"module\" src=\"https://unpkg.com/hover-video-player\" /\u003e`\n- iife build: `\u003cscript src=\"https://unpkg.com/hover-video-player/dist/index.client.js\" /\u003e`\n\n## Usage\n\nAll you need to do is import this library into your site/app and it will register a `hover-video-player` custom element which you can now use.\n\n### Examples\n\n\u003cdetails open\u003e\n  \u003csummary\u003eVanilla HTML\u003c/summary\u003e\n\n  ```html\n  \u003c!-- index.html --\u003e\n  \u003chtml\u003e\n    \u003chead\u003e\n      \u003cstyle\u003e\n        hover-video-player:not(:defined) {\n          /* Hide the hover-video-player element until the component is loaded and defined\n              so we can avoid getting a flash of unstyled content */\n          display: none;\n        }\n\n        hover-video-player img[slot=\"paused-overlay\"] {\n          object-fit: cover;\n        }\n      \u003c/style\u003e\n      \u003cscript type=\"module\" src=\"https://unpkg.com/hover-video-player\"\u003e\u003c/script\u003e\n    \u003c/head\u003e\n    \u003cbody\u003e\n      \u003chover-video-player\u003e\n        \u003cvideo src=\"path/to/video.mp4\" muted loop playsinline\u003e\u003c/video\u003e\n        \u003cimg\n          src=\"path/to/thumbnail.jpg\"\n          slot=\"paused-overlay\"\n        /\u003e\n      \u003c/hover-video-player\u003e\n    \u003c/body\u003e\n  \u003c/html\u003e\n  ```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003eWebC\u003c/summary\u003e\n\n  ```js\n  // .eleventy.js\n  eleventyConfig.addPlugin(pluginWebc, {\n    components: [\n      \"npm:hover-video-player/**/*.webc\",\n    ],\n  });\n  ```\n\n  ```html\n  \u003c!-- component.webc --\u003e\n  \u003chover-video-player\u003e\n    \u003cvideo src=\"path/to/video.mp4\" muted loop playsinline /\u003e\n    \u003cimg\n      src=\"path/to/thumbnail.jpg\"\n      class=\"paused-overlay\"\n      slot=\"paused-overlay\"\n    /\u003e\n  \u003c/hover-video-player\u003e\n  ```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003eSvelte\u003c/summary\u003e\n\n  ```html\n  \u003c!-- component.svelte --\u003e\n  \u003cscript\u003e\n    import \"hover-video-player\";\n  \u003c/script\u003e\n\n  \u003chover-video-player\u003e\n    \u003cvideo src=\"path/to/video.mp4\" muted loop playsinline /\u003e\n    \u003cimg\n      src=\"path/to/thumbnail.jpg\"\n      class=\"paused-overlay\"\n      slot=\"paused-overlay\"\n    /\u003e\n  \u003c/hover-video-player\u003e\n\n  \u003cstyle\u003e\n    hover-video-player:not(:defined) {\n      /* Hide the hover-video-player element until the component is loaded and defined\n          so we can avoid getting a flash of unstyled content */\n      display: none;\n    }\n\n    hover-video-player img[slot=\"paused-overlay\"] {\n      object-fit: cover;\n    }\n  \u003c/style\u003e\n\n  ```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003eVue\u003c/summary\u003e\n\n  See Vue's _[\"Using custom elements in Vue\"](https://vuejs.org/guide/extras/web-components.html#using-custom-elements-in-vue)_ documentation for details on how to set up your vue/vite config to support using custom elements.\n\n  ```html\n  \u003c!-- component.vue --\u003e\n  \u003cscript\u003e\n    import \"hover-video-player\";\n  \u003c/script\u003e\n\n  \u003ctemplate\u003e\n    \u003chover-video-player\u003e\n      \u003cvideo src=\"path/to/video.mp4\" muted loop playsinline /\u003e\n      \u003cimg\n        src=\"path/to/thumbnail.jpg\"\n        class=\"paused-overlay\"\n        slot=\"paused-overlay\"\n      /\u003e\n    \u003c/hover-video-player\u003e\n  \u003c/template\u003e\n\n  \u003cstyle\u003e\n    hover-video-player:not(:defined) {\n      /* Hide the hover-video-player element until the component is loaded and defined\n          so we can avoid getting a flash of unstyled content */\n      display: none;\n    }\n\n    hover-video-player img[slot=\"paused-overlay\"] {\n      object-fit: cover;\n    }\n  \u003c/style\u003e\n  ```\n\n\u003c/details\u003e\n\n### Slots\n\nCustom elements accept slots which can then be displayed as children of the component. `hover-video-player` has 4 slots:\n\n- **Default slot** (REQUIRED): The default unnamed slot requires a [video element](https://developer.mozilla.org/en-US/docs/Web/API/HTMLVideoElement) which the component will control. This provides a lot of flexibility so that you can configure the video however you see fit.\n\n  Recommended video attributes:\n  - `loop`: Makes the video loop back to the beginning and keep playing if it reaches the end\n  - `muted`: Makes sure the video will play without audio. Browsers may block playback with audio, so this can help prevent that from happening from the start\n  - `playsinline`: Makes sure that the video will be played where it is displayed on the page rather than being opened in fullscreen on iOS Safari\n  - `preload`: Makes sure that the browser doesn't attempt to aggressively pre-load the video until the user actually starts playing it. You should usually use `preload=\"metadata\"` as this will still load basic metadata such as the video's dimensions, which can be helpful for displaying the player with the right aspect ratio\n\n  ```html\n  \u003chover-video-player\u003e\n    \u003c!-- A video element is required for the component's default slot --\u003e\n    \u003cvideo\n      src=\"/path/to/video.mp4\"\n      loop\n      muted\n      playsinline\n      preload=\"metadata\"\n    \u003e\u003c/video\u003e\n  \u003c/hover-video-player\u003e\n  ```\n\n- **\"paused-overlay\"**: The \"paused-overlay\" slot is an optional named slot. It accepts contents which you want to display over the video while it is in a paused or loading state; when the video starts playing, this content will be faded out.\n\n  A common use case for this would be displaying a thumbnail image over the video while it is paused.\n\n  ```html\n  \u003chover-video-player\u003e\n    \u003cvideo src=\"/path/to/video.mp4\" /\u003e\n    \u003cimg src=\"/video-thumbnail.jpg\" slot=\"paused-overlay\" /\u003e\n  \u003c/hover-video-player\u003e\n  ```\n\n- **\"loading-overlay\"**: The \"loading-overlay\" slot is an optional named slot. It accepts contents which you want to display over the video if it in a loading state, meaning the user is attempting to play the video and it has taken too long to start.\n\n  This is useful if you want to show a loading state while the user is waiting for the video to play.\n\n  Note that the \"paused-overlay\" slot will still be displayed while the video is in a loading state; this overlay will simply be displayed on top of that one.\n\n  The exact loading state timeout duration can be set on a `--loading-timeout-duration` CSS variable. See [Loading State Timeouts](#loading-state-timeouts) for details.\n\n  ```html\n  \u003cstyle\u003e\n    hover-video-player {\n      /* The loading overlay should fade in if the video takes longer than 400ms to start\n          after the user hovers over the player */\n      --loading-timeout-duration: 400ms;\n    }\n  \u003c/style\u003e\n\n  \u003chover-video-player\u003e\n    \u003cvideo src=\"/path/to/video.mp4\" /\u003e\n    \u003cdiv slot=\"loading-overlay\"\u003e\n      \u003cdiv class=\"loading-spinner\" /\u003e\n    \u003c/div\u003e\n  \u003c/hover-video-player\u003e\n  ```\n\n- **\"hover-overlay\"**: The \"hover-overlay\" slot is an optional named slot. It accepts contents which you wnat to display over the video while the user is hovering on the player's hover target.\n\n  This is useful if you want to reveal content to the user when the user is hovering on the player's hover target while still allowing the video to play underneath.\n\n  Note that this overlay takes highest ordering priority and will be displayed on top of both the \"paused-overlay\" and \"loading-overlay\" slots if they are set.\n\n  ```html\n  \u003chover-video-player\u003e\n    \u003cvideo src=\"/path/to/video.mp4\" /\u003e\n    \u003cdiv slot=\"hover-overlay\"\u003eThe user is hovering!\u003c/div\u003e\n  \u003c/hover-video-player\u003e\n  ```\n\n#### Overlay customization\n\n##### Overlay transition durations\n\nThe time it takes for the component's overlays to fade in/out is dictated by the `--overlay-transition-duration` CSS variable. By default, its value is `0.4s`.\n\nIf you wish, you may customize the transition duration by setting your own value for this CSS variable.\n\nYou may set it on the root `hover-video-player` element's level to set the transition duration for all overlays, or you can target a specific overlay slot if you wish to have different transition durations for different overlays.\n\n```html\n\u003cstyle\u003e\n  hover-video-player {\n    /* All overlays should take 500ms to fade in and out */\n    --overlay-transition-duration: 500ms;\n  }\n\n  hover-video-player img[slot=\"paused-overlay\"] {\n    /* The paused overlay img element should take 1.5s to fade in and out */\n    --overlay-transition-duration: 1.5s;\n  }\n\u003c/style\u003e\n\n\u003chover-video-player\u003e\n  \u003cvideo src=\"/path/to/video.mp4\" /\u003e\n  \u003cimg src=\"/video-thumbnail.jpg\" slot=\"paused-overlay\" /\u003e\n  \u003cdiv slot=\"loading-overlay\"\u003eLoading...\u003c/div\u003e\n\u003c/hover-video-player\u003e\n```\n\n###### Loading state timeouts\n\nThe time that the component will wait before fading in the loading overlay if the video is taking a while to start is dictated by the `--loading-timeout-duration` CSS variable. By default, its value is `0.2s`.\n\nIf you wish, you may customize this timeout duration by setting your own value for this CSS variable either on the root `hover-video-player` element's level or directly on the loading overlay slot element.\n\n```html\n\u003cstyle\u003e\n  hover-video-player {\n    /* We should only wait 100ms before fading in the loading overlay */\n    --loading-timeout-duration: 100ms;\n  }\n\u003c/style\u003e\n\n\u003chover-video-player\u003e\n  \u003cvideo src=\"/path/to/video.mp4\" /\u003e\n  \u003cdiv slot=\"loading-overlay\"\u003eLoading...\u003c/div\u003e\n\u003c/hover-video-player\u003e\n```\n\n### Element API\n\n#### hover-target\n\nThe optional `\"hover-target\"` attribute can be used to provide a selector string for element(s) which the component should watch for hover interactions. If a hover target is not set, the component will use its root element as the hover target.\n\nNote that if you provide a selector which matches multiple elements in the document, they will all be added as hover targets.\n\nThe component's hover target can also be accessed and updated in JS with the `hoverTarget` property.\nThis property may be a single `Element` instance, or an iterable of `Element` instances; a manually constructed array, a `NodeList` returned by `querySelectorAll`, or an HTMLCollection returned by `getElementsByClassName` are all acceptable.\n\n```html\n\u003c!-- A single hover target --\u003e\n\u003cdiv id=\"hover-on-me\"\u003eHover on me to start playing!\u003c/div\u003e\n\u003chover-video-player hover-target=\"#hover-on-me\"\u003e\n  \u003cvideo src=\"video.mp4\" /\u003e\n\u003c/hover-video-player\u003e\n\n\u003c!-- Multiple hover targets --\u003e\n\u003cdiv class=\"hover-target\"\u003eYou can hover on me to play\u003c/div\u003e\n\u003cdiv class=\"hover-target\"\u003eYou can also hover on me!\u003c/div\u003e\n\u003chover-video-player hover-target=\".hover-target\"\u003e\n  \u003cvideo src=\"video.mp4\" /\u003e\n\u003c/hover-video-player\u003e\n```\n\nSetting with JS:\n\n```js\nconst player = document.querySelector(\"hover-video-player\");\n// Setting a single hover target element\nplayer.hoverTarget = document.getElementById(\"hover-on-me\");\n\n// Setting multiple hover targets\nplayer.hoverTarget = document.querySelectorAll(\".hover-target\");\n```\n\n#### restart-on-pause\n\nThe optional boolean `\"restart-on-pause\"` attribute will cause the component to reset the video to the beginning when the user ends their hover interaction. Otherwise, the video will remain at whatever time it was at when the user stopped hovering, and start from there if they hover to play it again.\n\nThis can also be accessed and updated in JS with the `restartOnPause` property.\n\n```html\n\u003chover-video-player restart-on-pause\u003e\n  \u003cvideo src=\"video.mp4\" /\u003e\n\u003c/hover-video-player\u003e\n```\n\nSetting with JS:\n\n```js\nconst player = document.querySelector(\"hover-video-player\");\nplayer.restartOnPause = true;\n```\n\n#### sizing-mode\n\nThe optional `\"sizing-mode\"` attribute has no effects on the component's behavior, but it provides a set of helpful style presets which can be applied to the player.\n\nValid sizing mode options are:\n\n- `\"video\"` (default): Everything should be sized based on the video element's dimensions; overlays will expand to cover the video.\n  - Note that this mode comes with a caveat: The video element may briefly display with different dimensions until it finishes loading the metadata containing the video's actual dimensions. This is usually fine when the metadata is loaded immediately, so it is recommended that you avoid using this mode in combination with the [unload-on-pause](#unload-on-pause) setting described below, as it will cause the video's metadata to be unloaded frequently.\n- `\"overlay\"`: Everything should be sized relative to the paused overlay slot's dimensions and the video will expand to fill that space.\n- `\"container\"`: The video and all overlays should be sized to cover the dimensions of the outermost `\u003chover-video-player\u003e` host element.\n- `\"manual\"`: All preset sizing mode styles are disabled, leaving it up to you.\n\n```html\n\u003chover-video-player sizing-mode=\"overlay\"\u003e\n  \u003cvideo src=\"video.mp4\" /\u003e\n  \u003c!-- The hover-video-player component will be sized relative to this thumbnail image's dimensions --\u003e\n  \u003cimg src=\"thumbnail.jpg\" slot=\"paused-overlay\" /\u003e\n\u003c/hover-video-player\u003e\n\n\u003c!-- The host element has a set 16:9 aspect ratio which the video and overlays should expand to cover --\u003e\n\u003chover-video-player sizing-mode=\"container\" style=\"aspect-ratio: 16 / 9;\"\u003e\n  \u003cvideo src=\"video.mp4\" /\u003e\n  \u003cimg src=\"thumbnail.jpg\" slot=\"paused-overlay\" /\u003e\n\u003c/hover-video-player\u003e\n```\n\n#### playback-start-delay\n\nThe optional `\"playback-start-delay\"` attribute can be used to apply a delay between when the user starts hovering and when the video starts playing.\n\nThis can be useful as an optimization if you have a page with a large number of `hover-video-player` instances and want to avoid making unnecessary requests to load video assets which may occur as the user browses arund the page and passes their mouse over videos that they don't intend to watch.\n\nThis attribute accepts times in the format of seconds like \"0.5s\", or milliseconds like \"100ms\" or simply \"100\".\n\nThis can also be accessed and updated in JS with the `playbackStartDelay` property.\n\n```html\n\u003chover-video-player playback-start-delay=\"100\"\u003e\n  \u003cvideo src=\"video.mp4\" /\u003e\n\u003c/hover-video-player\u003e\n```\n\nSetting with JS:\n\n```js\nconst player = document.querySelector(\"hover-video-player\");\nplayer.playbackStartDelay = 500;\n```\n\n#### unload-on-pause\n\n`hover-video-player` accepts an optional boolean `\"unload-on-pause\"` attribute which, if present, will cause the component to fully unload the video's sources when the video is not playing in an effort to reduce the amount of memory and network usage on the page.\n\nThis setting is necessary because when you pause a video after playing it for the first time, it remains loaded in memory and browsers will often continue loading more of the video in case the user goes back to play more of it. This is fine on a small scale, but in cases where you have a page with a very large number of `hover-video-player` instances, it may become necessary in order to prevent all of the videos on the page from eating up a ton of network bandwidth and memory all at once, causing significant performance degradation for the user.\n\nAlthough this setting can provide some performance benefits, it also has notable drawbacks:\n\nThe video's metadata will be (at least temporarily) fully unloaded when the video is paused, which could cause content jumps to occur when the video starts/stops playing.\n\nAs a result, it is recommended that you set the [`\"sizing-mode\"`](#sizing-mode) attribute to \"overlay\" or \"container\", or provide your own custom styles to set a fixed dimensions for the component.\n\nAdditionally, the video may not show a thumbnail/first frame, or if it does, it may flash in ways that are undesired. As a result, it is recommended to provide overlay contents for the \"paused-overlay\" slot which will hide the video element while it is paused and unloaded.\n\nThis setting must be paired with setting either `preload=\"metadata\"` or `preload=\"none\"` on the video element to make sure that the browser does not try to preload every video asset while it isn't playing. If a `preload` attribute is not set on the video, the component will set `preload=\"metadata\"` on it automatically.\n\nThis can also be accessed and updated in JS with the `unloadOnPause` property.\n\n```html\n\u003chover-video-player unload-on-pause sizing-mode=\"overlay\"\u003e\n  \u003cvideo src=\"video.mp4\" preload=\"none\" /\u003e\n  \u003cimg src=\"thumbnail.jpg\" /\u003e\n\u003c/hover-video-player\u003e\n```\n\nSetting with JS:\n\n```js\nconst player = document.querySelector(\"hover-video-player\");\nplayer.unloadOnPause = true;\n```\n\n#### controlled\n\nThe optional boolean `\"controlled\"` attribute will disable standard event handling on the hover target so playback can be fully manually managed programmatically for more complex custom behavior.\n\nYou can programmatically start and stop playback on a controlled component by using the `.hover()` and `.blur()` methods, or manipulating the [`\"data-playback-state\"`](#data-playback-state) attribute.\n\nThis option is essentially a shorthand for calling `event.preventDefault()` on both [`\"hoverstart\"`](#hoverstart) and [`\"hoverend\"`](#hoverend) events.\n\nThis can also be accessed and updated in JS with the `controlled` property.\n\n```html\n\u003chover-video-player controlled\u003e\n  \u003cvideo src=\"video.mp4\" /\u003e\n\u003c/hover-video-player\u003e\n```\n\nSetting with JS:\n\n```js\nconst player = document.querySelector(\"hover-video-player\");\nplayer.controlled = true;\n```\n\nProgrammatically starting/stopping playback:\n\n```js\nconst player = document.querySelector(\"hover-video-player\");\n// Start playback\nplayer.hover();\n// Stop playback\nplayer.blur();\n\n// Start playback\nplayer.dataset.playbackState = \"playing\";\n```\n\n### Data attributes\n\nThe component sets some data attributes on its element which expose some of the component's internal state for custom styling.\n\nIt is recommended that you do not tamper with these attributes by manually modifying them yourself, as the component\nwill likely overwrite your changes and these attributes are used internally for the component's styling.\n\n#### data-is-hovering\n\n`data-is-hovering` is a boolean data attribute which is present when the player is hovered, meaning it is actively playing or trying to play.\n\nIt will look like this in the DOM:\n\n```html\n\u003c!-- State while the user is not hovering --\u003e\n\u003chover-video-player\u003e\n  \u003cvideo src=\"video.mp4\" /\u003e\n\u003c/hover-video-player\u003e\n\n\u003c!-- State when the user is hovering --\u003e\n\u003chover-video-player data-is-hovering\u003e\n  \u003cvideo src=\"video.mp4\" /\u003e\n\u003c/hover-video-player\u003e\n```\n\n```css\nhover-video-player[data-is-hovering] {\n  /* When the player is being hovered, add custom styles to shift it up and add a box shadow */\n  transform: translateY(-5%);\n  box-shadow: 0px 0px 10px black;\n}\n```\n\n#### `data-playback-state`\n\n`data-playback-state` is an enum data attribute which reflects the video's internal playback state. The attribute can have one of the following values:\n\n- `\"paused\"`: The video is paused and not attempting to play\n- `\"loading\"`: The video is attempting to play, but still loading\n- `\"playing\"`: The video is playing\n\nIf you manipulate the value of the attribute, the component will attempt to transition to that playback state.\n\nIt will look like this in the DOM:\n\n```html\n\u003c!-- Initial state before the component has mounted --\u003e\n\u003chover-video-player\u003e\n  \u003cvideo src=\"video.mp4\" /\u003e\n\u003c/hover-video-player\u003e\n\n\u003c!-- State after the component has mounted but is not playing --\u003e\n\u003chover-video-player data-playback-state=\"paused\"\u003e\n  \u003cvideo src=\"video.mp4\" /\u003e\n\u003c/hover-video-player\u003e\n\n\u003c!-- State when the user is hovering and the video is playing --\u003e\n\u003chover-video-player data-is-hovering data-playback-state=\"playing\"\u003e\n  \u003cvideo src=\"video.mp4\" /\u003e\n\u003c/hover-video-player\u003e\n```\n\n```css\nhover-video-player[data-playback-state=\"paused\"] {\n  /* Red background when the player is paused */\n  background: red;\n}\n\nhover-video-player[data-playback-state=\"loading\"] {\n  /* Yellow background when the player is loading */\n  background: yellow;\n}\n\nhover-video-player[data-playback-state=\"playing\"] {\n  /* Green background when the player is playing */\n  background: green;\n}\n```\n\nThe attribute can be manipulated to trigger playback state updates. This could be combined with the `controlled` attribute\nas another way to manually control playback state via JavaScript.\n\n```js\nconst player = document.querySelector(\"hover-video-player\");\nconsole.log(player.dataset.playbackState); // \"paused\"\n// The player will attempt to play; it will revert back to a \"loading\" state until playback succeeds\nplayer.dataset.playbackState = \"playing\";\nconsole.log(player.dataset.playbackState); // \"loading\"\n// Once the video starts playing...\nconsole.log(player.dataset.playbackState); // \"playing\"\n\n// Removing the attribute or setting it to an invalid value will reset the player to \"paused\" state\nplayer.removeAttribute(\"data-playback-state\");\nconsole.log(player.dataset.playbackState); // \"paused\"\n```\n\n### Events\n\n#### `hoverstart`\n\nThe player component will emit a `\"hoverstart\"` event when a user hovers over the player's hover target to start playback. `\"hoverstart\"` events are cancelable `CustomEvents`.\n\nEach event will include the `Event` object from the originating hover target event on `event.detail`.\n\nIf you wish to intercept a `\"hoverstart\"` event and prevent the component from proceeding to start playback,\nyou can call `event.preventDefault()` in a `hoverend` listener. If the component is [controlled](#controlled),\nboth `\"hoverstart\"` and `\"hoverend\"` events will automatically be canceled without requiring any further action from you.\n\n```js\nconst player = document.querySelector(\"hover-video-player\");\nplayer.addEventListener(\"hoverstart\", (evt) =\u003e {\n  console.log(\"The user hovered!\");\n  if (shouldPreventPlay) {\n    // Call preventDefault to prevent the component from proceeding to start playback in response to this `hoverstart` event\n    evt.preventDefault();\n  }\n\n  console.log(\"The hoverstart interaction originated on this element:\", evt.detail.currentTarget);\n});\n```\n\n#### `hoverend`\n\nThe player component will emit a `\"hoverend\"` event when a user stops hovering over the player's hover target to stop playback. `\"hoverend\"` events are cancelable `CustomEvents`.\n\nEach event will include the `Event` object from the originating hover target event on `event.detail`.\n\nIf you wish to intercept a `\"hoverend\"` event and prevent the component from proceeding to pause playback,\nyou can call `event.preventDefault()` in a `hoverend` listener. If the component is [controlled](#controlled),\nboth `\"hoverstart\"` and `\"hoverend\"` events will automatically be canceled without requiring any further action from you.\n\n```js\nconst player = document.querySelector(\"hover-video-player\");\nplayer.addEventListener(\"hoverend\", (evt) =\u003e {\n  console.log(\"The user is no longer hovering!\");\n\n  if (shouldPreventPause) {\n    // Call preventDefault to prevent the component from proceeding to pause playback in response to this `hoverend` event\n    evt.preventDefault();\n  }\n\n  console.log(\"The hoverend interaction originated on this element:\", evt.detail.currentTarget);\n});\n```\n\n#### `playbackstatechange`\n\nThe player component will emit a custom `\"playbackstatechange\"` event when the player's playback state changes.\nThis is a `CustomEvent` where the `detail` will be the new playback state, matching the [`data-playback-state`](#data-playback-state) attribute.\n\n```js\nconst player = document.querySelector(\"hover-video-player\");\nplayer.addEventListener(\"playbackstatechange\", (evt) =\u003e {\n  console.log(\"The new playback state is...\", evt.detail);\n});\n```\n\n\n### Alternative media sources\n\nThe native `\u003cvideo\u003e` element is mostly oriented toward playing statically hosted video files,\nbut you may wish to use a different media source such as a YouTube video, Vimeo video, or even an m3u8 HLS video stream.\n\nThis component will support any custom video player element which implements core HTMLMediaElement APIs.\n[Mux maintains an incredibly good collection of media elements](https://github.com/muxinc/media-elements/tree/main) which do exactly that. Any of these custom elements should be able to be used in place of a `\u003cvideo\u003e` and work as expected.\n\n\u003e [!WARNING]\n\u003e\n\u003e Some of `hover-video-player`'s APIs are not designed to be used\n\u003e with custom elements and may have unexpected interactions.\n\u003e\n\u003e In particular, be careful with [`unload-on-pause`](#unload-on-pause),\n\u003e as it most likely will not be able to unload the video's source as expected.\n\u003e\n\u003e It is also worth noting that some of these custom elements may have issues with playback with audio. For instance, `youtube-element`\n\u003e may fail to play without the `muted` attribute unless you perform a click interaction on the element to play it first.\n\n#### Example: controlling a YouTube video\n\nUsing Mux's [`youtube-video`](https://github.com/muxinc/media-elements/tree/main/packages/youtube-video-element) custom element.\n\n```html\n\u003cscript\n  type=\"module\"\n  src=\"https://cdn.jsdelivr.net/npm/youtube-video-element@1\"\n\u003e\u003c/script\u003e\n\n\u003chover-video-player\u003e\n  \u003cyoutube-video\n    src=\"https://www.youtube.com/watch?v=aqz-KE-bpKQ\"\n    playsinline\n    muted\n  \u003e\u003c/youtube-video\u003e\n\u003c/hover-video-player\u003e\n```\n\n#### Example: controlling a Vimeo video\n\nUsing Mux's [`vimeo-video`](https://github.com/muxinc/media-elements/tree/main/packages/vimeo-video-element) custom element.\n\n```html\n\u003cscript\n  type=\"module\"\n  src=\"https://cdn.jsdelivr.net/npm/vimeo-video-element@1.0/+esm\"\n\u003e\u003c/script\u003e\n\n\u003chover-video-player\u003e\n  \u003cvimeo-video\n    src=\"https://vimeo.com/648359100\"\n  \u003e\u003c/vimeo-video\u003e\n\u003c/hover-video-player\u003e\n```\n\n#### Example: controlling an m3u8 HLS stream\n\nUsing Mux's [`hls-video`](https://github.com/muxinc/media-elements/tree/main/packages/hls-video-element) custom element.\n\n```html\n\u003cscript\n  type=\"module\"\n  src=\"https://cdn.jsdelivr.net/npm/hls-video-element@1.1/+esm\"\n\u003e\u003c/script\u003e\n\n\u003chover-video-player\u003e\n  \u003chls-video\n    src=\"https://stream.mux.com/r4rOE02cc95tbe3I00302nlrHfT023Q3IedFJW029w018KxZA.m3u8\"\n  \u003e\u003c/hls-video\u003e\n\u003c/hover-video-player\u003e\n```","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgyanreyer%2Fhover-video-player","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgyanreyer%2Fhover-video-player","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgyanreyer%2Fhover-video-player/lists"}