Video
<x-wirekit:: plays a video in the page. A file or a stream plays when the reader presses play, and a video on YouTube or Vimeo loads nothing from the provider until the reader has agreed to it. With background, a file runs as a muted loop with a pause button.
Basic Usage
Give the address, a title and the page's own still as the poster:
This video cannot play in this browser.
Nothing loads before the press: the element gets its address then, and the poster is the only file the page fetches, lazily. After the press the browser's own controls take over, and the focus moves to the video, so the keyboard controls it at once.
The title names the play button, "Play A short sample clip", and the player of a provider. Without one the video is called "Video".
YouTube and Vimeo
An address on YouTube or Vimeo plays in the provider's own player. Before the reader agrees, the page sends nothing to the provider: no player, no thumbnail, no script. A notice stands in its place, says which provider holds the video and that loading it sends data there, and offers "Load the video":
<x-wirekit::video :src="$video->url" :title="$video->title" />
YouTube plays from www., the address on which it sets no cookie until the video plays, and Vimeo with Do Not Track switched on in the player's address, which keeps it from tracking the session. Every address form works: youtube., youtu.be/…, /embed/…, /shorts/…, vimeo.com/… and player., an unlisted Vimeo video with its hash included. An address on either host without the id of one video is reported and renders nothing.
A provider shows no poster of its own, since fetching its thumbnail is already a request to it. Give poster to show a still of your own behind the play button.
Consent
The page decides whether the reader has agreed, and the player asks. Where the page knows it already, from the cookie of its consent manager, it says so with consented, and the play button loads the player:
<x-wirekit::video
:src="$video->url"
:title="$video->title"
:poster="$video->poster_url"
:consented="request()->cookie('consent_youtube') === 'yes'"
/>
Where it does not, the notice offers "Load the video". The press sends wirekit:video-consent from the player, and it bubbles. Its detail carries name, the name of the consent, and provider, youtube or vimeo:
- Not canceled, the press is the consent for this one video, and its player loads at once. Without a consent manager on the page this is all that happens, the two-click pattern.
- Canceled, your consent manager has taken the question. It asks in its own way and answers on
windowwithwirekit:consent, whosedetailcarriesnameandgranted.
document.addEventListener('wirekit:video-consent', (event) => {
// 1. Take the question from the player.
event.preventDefault();
// 2. Ask in your own way; confirm() stands in for your consent manager here.
const granted = window.confirm(`Load videos from ${event.detail.provider}?`);
// 3. Tell every player on the page what the reader chose.
window.dispatchEvent(new CustomEvent('wirekit:consent', {
detail: { name: event.detail.name, granted },
}));
});
A player that waits for its consent loads the moment granted is true, and a player whose consent is withdrawn later, granted: false, removes the provider's player and shows its notice again. consent sets the name the player listens for, youtube or vimeo by default:
<x-wirekit::video :src="$video->url" :title="$video->title" consent="external-media" />
A Stream
An address that ends in .m3u8 is a stream (HLS), which changes its quality with the connection. Safari plays it as it is. Every other browser needs hls.js. Load its own build on the page, which sets window.Hls, or install it and hand it over from your bundle:
npm install hls.js
// resources/js/app.js
import Hls from 'hls.js';
import { registerHlsEngine } from '../../vendor/pushery/wirekit/dist/wirekit.esm.js';
registerHlsEngine(Hls);
A player that mounted before the library arrived plays once it is there. Where no browser and no library can play the stream, the player says so in a sentence instead of the video.
Captions
A video with sound needs captions (WCAG 1.2.2). tracks takes them as the <track> elements of the video, each with src and, as it needs them, srclang, label, kind (captions, subtitles or descriptions, captions by default) and default:
<x-wirekit::video
src="/videos/assembly.mp4"
title="Assembling the shelf"
:tracks="[
['src' => '/videos/assembly.en.vtt', 'srclang' => 'en', 'label' => 'English', 'default' => true],
['src' => '/videos/assembly.de.vtt', 'srclang' => 'de', 'label' => 'Deutsch'],
]"
/>
The track marked default shows from the start, and the browser's controls switch between them. A video on YouTube or Vimeo carries the captions the provider has for it.
A Muted Loop
With background a file or a stream plays muted and looped, without controls, as the backdrop of a section. It starts when a quarter of it is in view and pauses when it leaves. A button in its corner pauses it (WCAG 2.2.2):
This video cannot play in this browser.
A reader who asked for less motion (prefers-reduced-motion: reduce) or to save data (Save-Data) sees the poster, and the button plays the loop if they want it. Once the reader paused it, the loop stays paused when it comes back into view. A loop whose file fails after it started, such as a response that breaks off, stops and shows the poster again, and the button offers to play it. A provider's player cannot be a loop, and background on one is reported.
Ratio
The box holds its ratio before anything loads, 16 by 9 unless ratio says otherwise: 16/9, 4/3, 1/1, 9/16 for an upright phone video, or 21/9. A video of another shape is fitted inside the box, and the poster covers it:
This video cannot play in this browser.
Content Security Policy
A page with a frame-src directive allows the two hosts the players load from, www. and player.. A stream played through hls.js also needs its host in connect-src and media-src, with blob: in media-src.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
src |
string |
— | A file, a stream (.m3u8) or a video on YouTube or Vimeo. Without one nothing renders, and it is reported |
title |
string|null |
"Video" | The video's name: the play button's and the provider player's |
poster |
string|null |
null |
Your own still, shown until the video plays |
ratio |
string |
'16/9' |
16/9, 4/3, 1/1, 9/16 or 21/9 |
tracks |
array |
[] |
Captions and subtitles. See Captions |
background |
bool |
false |
A muted loop with a pause button. See A Muted Loop |
consented |
bool |
false |
Whether the page holds the reader's consent for the provider. See Consent |
consent |
string|null |
the provider | The name of the consent the player listens for |
scope |
string|null |
null |
Scoped personalization key |
Events
| Event | Detail | When |
|---|---|---|
wirekit:video-consent |
{ name, provider } |
The reader pressed "Load the video". Cancel it to answer with wirekit:consent yourself |
The player listens on window for wirekit:consent, { name, granted }, which your consent manager sends. See Consent.
Accessibility
- The play button is named after the video, "Play A short sample clip", and the player of a provider takes the title as its name.
- After the press the focus goes to the video or to the provider's player, so the keyboard reaches its controls without a search.
- The notice says which provider holds the video and that loading it sends data there, so the choice is an informed one.
- The button of a loop names what it does now, "Pause the video" or "Play the video", and stays in the tab order. A loop never starts under
prefers-reduced-motion. - Captions from
tracksshow from the start where one is markeddefault.
Keyboard Interaction
| Key | Action |
|---|---|
Tab |
Moves to the play button, the notice's button or the button of a loop |
Enter / Space |
Presses it. After the play button, the video or the provider's player has the focus |