Web component
Put a video on any web page with one script and one tag: <video-player>. It plays the same player as the dashboard and the gallery, with the voice-over, the captions and the controls.
Quick start
- 1Add the scriptOnce per page. It is small (a few kilobytes) and only defines the tag. The player itself is downloaded when a video comes into view.
- 2Add the tagPoint
srcat a video. Here it is the ad for Videobana, one of the gallery examples.
<script src="https://www.bana.video/widget.js" async></script>
<video-player src="https://www.bana.video/api/examples/ads-videobana"></video-player>The demos on this page do not start by themselves, so the page stays quiet. Your tag does, unless you write autoplay="false".
Where the video comes from
The tag accepts the video in four ways. They can be combined with a change of mind later: set spec or src from your code and the new video replaces the old one.
<!-- A video of the platform, or any JSON file that your site or another one serves -->
<video-player src="https://www.bana.video/api/public/videos/0123456789abcdef"></video-player>
<video-player src="/videos/launch.json"></video-player>| Address or JSON | What you get |
|---|---|
https://www.bana.video/api/public/videos/<id> | A video you made public in the dashboard. Its voice-over, timing and pictures come with it. The Share dialog has a ready-made snippet (the Web component tab). |
https://www.bana.video/api/examples/<id> | Any video of the gallery, with its recorded voice-over. The id is the last part of its gallery address. |
| A JSON file, or JSON text | The video document, as described in the JSON format. It is checked first; a problem is shown in the frame, with its place in the document, and sent as an error event. |
Options
Everything is an attribute, so it works in plain HTML, and a property of the same name, so it works from code. Yes/no options follow the HTML way: loop alone is yes, and loop="false" (or 0) is no. The last form is the only way to switch off something that is on by default, such as autoplay.
| Attribute | Property | Default | What it does |
|---|---|---|---|
src | src | – | The address of the video. A video of the platform, one of the gallery examples, or any JSON file. |
spec | spec | – | The video itself, as JSON text. The property also takes an object. It wins over src. |
captions | captions | off | Show the subtitles. The viewer can still switch them with the button. |
autoplay | autoplay | on | Start by itself when it comes into view. autoplay="false" shows the title card with a Watch button. |
loop | loop | off | Start again when it ends. |
muted | muted | off | Start without sound. The viewer can turn it on. |
volume | volume | 1 | From 0 to 1. |
playback-rate | playbackRate | 1 | Speed, from 0.25 to 4. |
controls | controls | all | The control bar: none, or a list of its parts. See below. |
fit | – | width | How the picture fills the element: width, contain or cover. See below. |
aspect | – | the video's | Show the video in another shape: 16:9, 9:16, 1:1, 4:5 and the others the platform exports. |
Controls
The bar is whole by default. controls="none" hides it (the video then plays by itself and a script can drive it), and a list keeps only some parts. The viewer's keyboard shortcuts follow the same list, and so does a click on the picture (it plays and pauses when play is there): space and K need play, the arrows need seek, M needs volume, F needs fullscreen, C needs captions.
| Part | What it is |
|---|---|
play | Play and pause. |
chapters | Previous and next scene. |
time | The time and the length. |
seek | The bar to jump around, with a mark for every scene. |
captions | The subtitles button. |
speed | The playback speed button. |
volume | Mute, and the volume slider. |
fullscreen | Full screen. |
<video-player src="…" captions controls="play time fullscreen"></video-player>Autoplay and sound
Browsers refuse to start sound on a page that nobody has clicked yet. The tag tries to play with sound, and when the browser says no it plays the video muted and shows a button, Sound is off · Tap to turn it on. After the visitor has used the page (a click anywhere is enough) the next video starts with sound. If you want no sound at all, say so with muted: that is also what a background video should do.
Fit and size
The tag is a block that is as wide as its container. fit says what the picture does inside it:
| fit | The picture | Use it for |
|---|---|---|
width | is as wide as the element, and as tall as it needs, with the control bar under it. The element has no height of its own. | Articles, landing pages, documentation. |
contain | fits whole inside the height you give the element, with bars where the shapes differ. | A fixed slot: a sidebar, a modal, a card. |
cover | fills the element and is cropped where the shapes differ. No control bar unless you ask for one. | Hero sections and backgrounds. |
With contain and cover the element is 16:9 until you give it a height (height, min-height or a grid or flex layout that sizes it). aspect shows a video in another shape than it was made for.
As a hero section
Whatever you write between the tags is put over the picture, so the tag can be the whole hero: the video fills it, and your headline and buttons stay your own HTML (indexable, translatable, styled by your CSS). Put the text in a panel or a gradient that keeps it readable over every scene.
<script src="https://www.bana.video/widget.js" async></script>
<style>
.hero { height: 70vh; min-height: 24rem; }
.hero-copy { align-self: center; max-width: 34rem; margin-left: 6vw; color: #fff; }
.hero-copy h1 { font-size: clamp(2rem, 5vw, 3.5rem); line-height: 1.05; }
</style>
<video-player class="hero" src="https://www.bana.video/api/examples/ads-videobana" fit="cover" muted loop>
<div class="hero-copy">
<h1>Make videos from words.</h1>
<p>Describe a topic. Get a narrated, animated video.</p>
<a href="/signup">Start for free</a>
</div>
</video-player>Make videos from words.
This text is the page's own. The video plays behind it.
muted loopmakes it a background: it starts everywhere, even where sound is refused, and never ends. Leavemutedout for a hero whose voice-over you want heard; the sound button shows when the browser blocks it.- The slot is a grid that fills the element:
align-self,justify-selfandplace-selfon your child place it, and clicks go through to the video everywhere your content is not. - Only a video that is shown starts: the tag waits until it is near the viewport, so a hero below the fold costs nothing until it is scrolled to.
From JavaScript
The tag behaves like a <video>: the same names for the same things.
const player = document.querySelector("video-player");
player.addEventListener("ready", () => console.log("length:", player.duration, "seconds"));
player.addEventListener("ended", () => console.log("done"));
player.addEventListener("error", (event) => console.warn(event.detail.message));
document.querySelector("#watch").addEventListener("click", async () => {
player.muted = false; // a click is what lets a browser play sound
player.currentTime = 0;
await player.play();
});| Member | What it is |
|---|---|
play() / pause() | Start and pause. play() also loads the video, even when the element is not on screen. |
currentTime | Where the video is, in seconds. Set it to jump. |
duration, paused, ended | Read-only state. duration is NaN until the video has loaded. |
muted, volume, playbackRate, loop, autoplay, captions, controls | The options above, readable and writable. |
src, spec | Change the video. Setting either starts the new video over. |
error | Why the video cannot be shown, or null. |
| Event | When |
|---|---|
ready | The video has been loaded. duration is now known. |
play | It started or resumed, whoever caused it. |
pause | It was paused. |
ended | It reached the end (with loop it starts again, and ended still fires). |
volumechange | Muted or the volume changed, by the viewer or by your code. |
ratechange | The playback speed changed. |
error | The video could not be shown. event.detail.message says why. |
Styling
The player lives in a shadow root, so your page's CSS cannot break it and its CSS cannot touch your page. You size and place the tag like any block, and two variables restyle it:
video-player {
--vp-radius: 20px; /* corners (12px when it is as wide as the page, square for contain and cover) */
--vp-letterbox: #0b0b12; /* the bars of fit="contain" and fit="cover" */
max-width: 960px;
margin-inline: auto;
}On your platform
The script goes in once, the tag goes where the video should be. Pick yours:
<!doctype html>
<html>
<body>
<video-player src="https://www.bana.video/api/examples/ads-videobana"></video-player>
<!-- once per page, anywhere -->
<script src="https://www.bana.video/widget.js" async></script>
</body>
</html>Good to know
- Other sites need permission to read your JSON. The platform's script, public videos and examples answer every origin. If you host a JSON file yourself on another domain, it must send
Access-Control-Allow-Origin. - Content-Security-Policy. Allow
https://www.bana.videoinscript-src(the widget loads a second file from the same place), inconnect-src(the video), and inimg-srcandmedia-src(pictures and the voice-over). The player's own styles are applied without<style>elements, sostyle-srcneeds nothing for them. - Fonts come from Google Fonts, loaded when a video needs them (the families a video uses, no others). They need
style-src https://fonts.googleapis.comandfont-src https://fonts.gstatic.com; a policy that blocks them gets system fonts instead. - Browsers: current Chrome, Edge, Firefox and Safari (custom elements, shadow DOM and ES2022).
- The script is cached, the player is cached for good. Its file name carries a hash of its content, so a new release is picked up by the next load of
https://www.bana.video/widget.jswithout any change on your side. Load the script from the platform's address; do not copy it.
error event: an address that is wrong or blocked (CORS), a video that is not public, or a document that fails the checks. The script tag <script src="https://www.bana.video/widget.js" async></script> must be on the same page, and the tag must be <video-player> with a dash.An example to start from: https://www.bana.video/api/examples/ads-videobana opens as JSON and is the payload the tag reads. To embed in a place that cannot run scripts, use the iframe from the Share dialog instead (see the HTTP API for the embed and oEmbed addresses).