RecipesBranded controls
Branded controls
Hide the built-in controls and render your own UI on top of the player.
When the default controls don't fit your brand, render your own. Hide
the native UI with controls=0 and forward viewer interactions to the
Player API.
Pattern
<div class="player-shell">
<iframe
src="https://watch.moviie.ai/embed/VIDEO_ID?controls=0"
title="Moviie Player"
allow="autoplay; fullscreen; picture-in-picture"
allowfullscreen
></iframe>
<div class="custom-controls">
<button data-action="toggle-play">Play / Pause</button>
<button data-action="toggle-mute">Mute / Unmute</button>
<button data-action="toggle-fullscreen">Fullscreen</button>
<input data-action="seek" type="range" min="0" max="100" value="0" />
</div>
</div>Wire up the controls
const iframe = document.querySelector("iframe")
const seek = document.querySelector('[data-action="seek"]')
function withPlayer(callback) {
const moviie = iframe.contentWindow?.Moviie
if (moviie) callback(moviie)
}
document
.querySelector('[data-action="toggle-play"]')
.addEventListener("click", () => withPlayer((moviie) => moviie.togglePlay()))
document
.querySelector('[data-action="toggle-mute"]')
.addEventListener("click", () => withPlayer((moviie) => moviie.toggleMute()))
document
.querySelector('[data-action="toggle-fullscreen"]')
.addEventListener("click", () =>
withPlayer((moviie) => moviie.toggleFullscreen()),
)
seek.addEventListener("input", (event) => {
withPlayer((moviie) => {
const ratio = Number(event.target.value) / 100
moviie.seek(moviie.duration * ratio)
})
})
iframe.addEventListener("load", () => {
withPlayer((moviie) => {
moviie.on("timeupdate", ({ currentTime }) => {
seek.value = String((currentTime / moviie.duration) * 100)
})
})
})Keep your UI in sync
Drive every visual indicator from player events instead of relying on DOM state:
play/pause→ toggle the play button icon.volumechange→ toggle the mute icon and slider position.fullscreenenter/fullscreenexit→ toggle the fullscreen icon.qualitychange→ highlight the active option in your settings menu.
This keeps the UI consistent even when the viewer triggers state changes through keyboard shortcuts or the operating system controls (PiP, media keys, etc.).