Kempo UI Icon Kempo UI

Kempo UI

Kempo UI Icon
Base Components
Utils

Video

Table of Contents

A <video> wrapper with no native controls. Build your own toolbar by slotting in the bundled kc-vid-* controls (or your own custom elements) — exactly the same slotted-control pattern used by Table, Pagination, and Markdown Editor. Use the controls attribute for a preconfigured toolbar, or mix and match.

Because there's no native <input type="range"> seek bar, there's nothing for the browser to give keyboard focus to when the user drags it — so a page-level keydown listener (e.g. space bar to play/pause) keeps working after the user interacts with the player. See Page-Level Keyboard Shortcut below.

Basic Usage

With no controls attribute and nothing slotted in, k-video renders just the bare video — useful when you want full control over the UI, or are driving playback entirely from your own buttons.

<k-video src="../media/evo.mp4" poster="../media/evo-mp4.png"></k-video>

Manual Controls

Slot any combination of built-in controls directly inside <k-video>, into one of three regions: unnamed (default) slot content renders in a control bar overlaid at the bottom of the player, slot="top" renders above the video, and slot="center" renders centered over the video — the last is where <kc-vid-play-big> normally goes.

<k-video src="../media/evo.mp4" poster="../media/evo-mp4.png" style="max-width: 480px;">
<kc-vid-play-big slot="center"></kc-vid-play-big>
<kc-vid-play-pause></kc-vid-play-pause>
<kc-vid-time></kc-vid-time>
<kc-vid-seek></kc-vid-seek>
<kc-vid-duration></kc-vid-duration>
<kc-vid-volume></kc-vid-volume>
<kc-vid-loop></kc-vid-loop>
<kc-fullscreen></kc-fullscreen>
</k-video>

Minimal Preconfigured

Use controls="minimal" for play/pause, a scrub bar, current time / duration, and fullscreen. A slot="center" big play/replay button is included by default.

<k-video src="../media/evo.mp4" poster="../media/evo-mp4.png" controls="minimal" style="max-width: 480px;"></k-video>

Normal Preconfigured

Use controls="normal" to add volume, playback speed, and loop on top of the minimal set.

<k-video src="../media/evo.mp4" poster="../media/evo-mp4.png" controls="normal" style="max-width: 480px;"></k-video>

Full Preconfigured

Use controls="full" for everything: skip forward/backward, download, volume, speed, loop, and Picture-in-Picture. Skip duration is customizable via skip-duration (default: 10 seconds).

<k-video src="../media/evo.mp4" poster="../media/evo-mp4.png" controls="full" style="max-width: 480px;"></k-video>

Use <kc-vid-menu> to group controls into a dropdown menu, saving toolbar space. The menu button displays a customizable icon and opens a dropdown containing your slotted controls. This is useful for grouping less-frequently-used options like download, loop, or Picture-in-Picture.

<k-video src="../media/evo.mp4" poster="../media/evo-mp4.png" style="max-width: 480px;">
<kc-vid-play-big slot="center"></kc-vid-play-big>
<kc-vid-play-pause></kc-vid-play-pause>
<kc-vid-seek></kc-vid-seek>
<kc-vid-volume></kc-vid-volume>
<kc-vid-menu icon="settings">
<kc-vid-speed>Speed</kc-vid-speed>
<kc-vid-loop>Loop</kc-vid-loop>
<kc-vid-pip>Picture-in-Picture</kc-vid-pip>
<kc-vid-download>Download</kc-vid-download>
</kc-vid-menu>
<kc-fullscreen></kc-fullscreen>
</k-video>
Speed Loop Picture-in-Picture Download

Combining Time and Duration

Slot <kc-vid-time> and <kc-vid-duration> next to each other (with a literal / between them) for a familiar “1:00 / 2:25” readout.

<k-video src="../media/evo.mp4" poster="../media/evo-mp4.png" style="max-width: 480px;">
<kc-vid-play-pause></kc-vid-play-pause>
<kc-vid-seek></kc-vid-seek>
<span class="time-combo">
<kc-vid-time></kc-vid-time> / <kc-vid-duration></kc-vid-duration>
</span>
<kc-fullscreen></kc-fullscreen>
</k-video>
/

Big Play Button

<kc-vid-play-big> shows a large centered play button (or a replay icon once playback ends) whenever the player is paused — the same pattern used by YouTube and most native players. Clicking anywhere on the video still toggles play/pause as usual. It's slotted into slot="center" and included by default in the minimal, normal, and full preconfigured sets (see above); it also works standalone with no other controls at all:

<k-video src="../media/evo.mp4" poster="../media/evo-mp4.png" style="max-width: 480px;">
<kc-vid-play-big slot="center"></kc-vid-play-big>
</k-video>

Double-Click to Seek

Double-click (or double-tap) the left half of the video to rewind, or the right half to skip forward — the same convention used by YouTube and most native players. A brief icon flashes on the side that was clicked. By default, skips 10 seconds; customize both the skip duration and flash indicator duration with attributes. This is always on, no attribute required to enable it.

<k-video src="../media/evo.mp4" poster="../media/evo-mp4.png" controls="normal" skip-duration="5" skip-flash-ms="300"></k-video>

Auto-Hide Controls

The control bar fades out after a couple of seconds of no mouse movement while the video is playing, and reappears instantly on mouse movement or whenever playback pauses. Customize the delay before auto-hide with the idle-delay-ms attribute. This is always on — play the video below and hold your mouse still over it.

<k-video src="../media/evo.mp4" poster="../media/evo-mp4.png" controls="normal" idle-delay-ms="5000"></k-video>

Buffering Indicator

A spinner automatically appears over the video whenever the browser has to pause for buffering (the native waiting event) and disappears once playback can resume (playing / canplay) — handy on slower connections or with kempo-server's HTTP Range-backed seeking. Nothing to configure; it's driven entirely by the underlying <video> element's own buffering state.

Custom Sizes & Aspect Ratios

By default k-video sizes itself to the video's own aspect ratio. If you force it into a width/height that doesn't match — a fixed-size player showing videos of varying dimensions, for example — the video letterboxes or pillarboxes to fit, centered both ways, with k-video's own black background filling the bars. It never stretches or crops the content.

<k-video src="../media/evo.mp4" poster="../media/evo-mp4.png" controls="normal" style="width: 480px; height: 200px;"></k-video>
<k-video src="../media/evo.mp4" poster="../media/evo-mp4.png" controls="normal" style="width: 200px; height: 400px;"></k-video>

Resume Playback Position

Set persistent-id to remember the playback position in localStorage and resume from there next time this player loads — the same persistent-id convention used by Tabs, Accordion, and Split. Play the video below, seek somewhere, then reload this page — it picks up where you left off. The saved position clears automatically once playback reaches the end.

<k-video src="../media/evo.mp4" poster="../media/evo-mp4.png" controls="normal" persistent-id="docs-demo" style="max-width: 480px;"></k-video>

Page-Level Keyboard Shortcuts

A common pattern: a global handler that maps keys to player methods. With a native <video controls>, dragging the native seek bar focuses it, and further key presses toggle that control instead of bubbling up to your page handler. k-video has no native controls to capture focus — its bundled kc-vid-seek is built on k-slider, which doesn't handle these keys, so they bubble up to document as expected. The e.target === document.body guard keeps this from firing while focus is on some other element (a text input, etc.).

<k-video id="player" src="../media/evo.mp4" poster="../media/evo-mp4.png" controls="normal"></k-video>
<script>
// Page-level shortcuts — work even after the user drags the seek bar,
// because k-video has no native <input type="range"> to steal focus.
document.addEventListener('keydown', (e) => {
if (e.target !== document.body) return;
const player = document.getElementById('player');
switch (e.code) {
case 'Space':
case 'KeyK':
e.preventDefault();
player.togglePlayPause();
break;
case 'ArrowLeft':
e.preventDefault();
player.skip(-5);
break;
case 'ArrowRight':
e.preventDefault();
player.skip(5);
break;
case 'ArrowUp':
e.preventDefault();
player.setVolume(player.volume + 0.1);
break;
case 'ArrowDown':
e.preventDefault();
player.setVolume(player.volume - 0.1);
break;
case 'KeyM':
player.toggleMute();
break;
case 'KeyF':
player.toggleFullscreen();
break;
}
});
</script>

JavaScript Reference

Constructor

new Video();

Requirements

Import the main component. When using controls, import each control individually or use the controls attribute, which auto-imports all required control modules.

Properties

Property / AttributeTypeDefaultDescription
srcString''URL of the video source.
posterString''Image shown before playback starts.
preloadString'metadata'Native preload hint: 'none', 'metadata', or 'auto'.
autoplayBooleanfalseAttempts to play automatically once a source is available (most browsers require muted as well).
loopBooleanfalseReplays from the start when playback ends. Toggling fires loop-changed.
mutedBooleanfalseMutes audio output.
playsinlineBooleantruePlays inline on mobile browsers instead of forcing fullscreen.
crossoriginString''Native crossorigin passthrough ('anonymous' / 'use-credentials').
downloadName / download-nameString''Suggested filename used by download().
volumeNumber1Playback volume from 0 to 1. Prefer setVolume(), which also handles unmuting.
playbackRate / playback-rateNumber1Playback speed multiplier.
fullscreenBooleanfalseTrue while the player is the fullscreen element. Read-only in practice — use the fullscreen methods to change it.
pictureInPicture / picture-in-pictureBooleanfalseTrue while the player is in Picture-in-Picture. Read-only in practice — use the Picture-in-Picture methods to change it.
controlsString''Preconfigured control set: 'minimal', 'normal', 'full', or 'none'/empty for none.
persistentId / persistent-idStringnullWhen set, remembers currentTime in localStorage and restores it on load. Cleared automatically when playback reaches the end.
idleDelayMs / idle-delay-msNumber2500Milliseconds before control bar fades out during playback. Set to 0 to disable auto-hide.
skipFlashMs / skip-flash-msNumber600Milliseconds to display the skip indicator after double-clicking.
skipDuration / skip-durationNumber10Seconds to skip forward or backward on double-click.
currentTimeNumber0Current playback position in seconds. Get/set directly, or use seek().
durationNumber0Total duration in seconds. Read-only.
pausedBooleantrueWhether playback is paused. Read-only.
endedBooleanfalseWhether playback has reached the end. Read-only.

Methods

MethodDescription
play()Starts (or resumes) playback. Chainable; swallows the rejected promise some browsers return when playback is blocked.
pause()Pauses playback. Chainable.
togglePlayPause()Plays if paused/ended, otherwise pauses. This is what <kc-vid-play-pause> calls.
seek(time)Jumps to time seconds, clamped to [0, duration].
skip(seconds)Seeks relative to the current position (negative to rewind).
setVolume(volume)Sets volume, clamped to [0, 1]. Automatically unmutes when raised above 0.
mute()Mutes the player.
unmute()Unmutes the player.
toggleMute()Flips the muted state.
setPlaybackRate(rate)Sets playback speed, clamped to [0.25, 4].
toggleLoop()Flips the loop property and fires loop-changed.
enterFullscreen()Requests fullscreen on the <k-video> element itself (not the bare <video>) so slotted controls stay visible.
exitFullscreen()Exits fullscreen if this player is the fullscreen element.
toggleFullscreen()Enters or exits fullscreen based on current state.
enterPictureInPicture()Requests Picture-in-Picture on the underlying <video> element.
exitPictureInPicture()Exits Picture-in-Picture if this player is the active element.
togglePictureInPicture()Enters or exits Picture-in-Picture based on current state.
download()Triggers a browser download of src using a temporary anchor, named via downloadName when set.

Events

EventDetailDescription
fullscreen-changed{ fullscreen }Fired when entering or exiting fullscreen.
picture-in-picture-changed{ pictureInPicture }Fired when entering or exiting Picture-in-Picture.
loop-changed{ loop }Fired when the loop property changes.
restored{ time }Fired once, when a saved position is restored from persistent-id.
play / pause / playing / endedForwarded directly from the underlying <video> element.
timeupdateForwarded from the underlying video; fires frequently during playback.
durationchange / loadedmetadataForwarded once media metadata is available — useful for reading duration.
volumechange / ratechangeForwarded when volume/mute or playback rate change, whether from your code or browser policy (e.g. forced autoplay muting).
seeking / seeked / waiting / progress / canplay / errorForwarded as-is from the underlying video element.
enterpictureinpicture / leavepictureinpictureForwarded as-is from the underlying video element.

Built-in Controls

Each control is a separate custom element that finds its parent <k-video> and wires up automatically. Import only the controls you need.

TagImportDescription
<kc-vid-play-pause>controls/VidPlayPause.jsToggles playback. Shows a play or pause icon based on host.paused.
<kc-vid-play-big>controls/VidPlayBig.jsLarge centered play/replay button, only rendered while paused. Belongs in slot="center".
<kc-vid-seek>controls/VidSeek.jsScrub bar built on k-slider. Grows to fill available space in the toolbar.
<kc-vid-time>controls/VidTime.jsCurrent playback position, formatted as m:ss (or h:mm:ss).
<kc-vid-duration>controls/VidDuration.jsTotal duration, same formatting as kc-vid-time. Slot them next to each other for a "1:00 / 2:25" readout.
<kc-vid-mute>controls/VidMute.jsA plain mute/unmute toggle button with no popup.
<kc-vid-volume>controls/VidVolume.jsMute button that reveals a popup vertical volume slider on hover, like a native player.
<kc-vid-speed>controls/VidSpeed.jsA playback-rate select (0.25x–2x).
<kc-vid-loop>controls/VidLoop.jsToggles loop. Reflects an active attribute while looping is enabled.
<kc-vid-download>controls/VidDownload.jsDownloads the current src.
<kc-vid-skip-back> / <kc-vid-skip-forward>controls/VidSkipBack.js / VidSkipForward.jsJump 10 seconds backward/forward.
<kc-vid-pip>controls/VidPip.jsToggles Picture-in-Picture. Reflects an active attribute while in Picture-in-Picture.
<kc-vid-menu>controls/VidMenu.jsMenu button that opens a dropdown containing slotted child controls. Customize the icon with the icon attribute (default: more_vert). Useful for grouping less-common controls to save toolbar space.
<kc-fullscreen>controls/controls/Fullscreen.jsThe same generic fullscreen control used by other kempo components — works with k-video without modification.