← All posts

Tutorials

Force native controls on every video

Custom video players look slick until they break: a missing scrubber, no volume slider, a play button that ignores clicks. The browser ships a reliable control bar for free. A JustZix rule forces it onto every video so you always have working controls.

The one property that matters

Every <video> element has a boolean controls property. When it is true, the browser draws its own control bar. Sites disable it so their custom UI can take over. Turn it back on:

document.querySelectorAll('video').forEach(function (v) {
  v.controls = true;
});

That is the core. The recipes below make it stick on dynamic pages and stop the site from removing it again.

Keep controls on dynamic players

Many sites toggle controls off after the page loads, or replace the video element entirely. A MutationObserver that watches both new nodes and attribute changes keeps your setting in place.

(function () {
  function force(v) {
    if (v.controls !== true) { v.controls = true; }
  }
  function scan(root) {
    if (root.tagName === 'VIDEO') { force(root); }
    if (root.querySelectorAll) {
      root.querySelectorAll('video').forEach(force);
    }
  }
  scan(document.documentElement);
  new MutationObserver(function (records) {
    records.forEach(function (rec) {
      if (rec.type === 'attributes' && rec.target.tagName === 'VIDEO') {
        force(rec.target);
      }
      rec.addedNodes.forEach(function (n) {
        if (n.nodeType === 1) { scan(n); }
      });
    });
  }).observe(document.documentElement, {
    childList: true,
    subtree: true,
    attributes: true,
    attributeFilter: ['controls']
  });
})();

The attributeFilter narrows the observer to just the controls attribute, so it stays cheap even on busy pages.

Hide the broken custom UI with CSS

Once the native bar is visible, the site's custom overlay often sits on top and steals clicks. A small CSS rule can push it out of the way. Custom controls usually carry a predictable class or data attribute; inspect the page once and target it.

.video-player .custom-controls,
[data-player-ui],
.vjs-control-bar {
  display: none !important;
}

video {
  pointer-events: auto !important;
}

The second block re-enables clicks on the video itself, in case the site disabled them so its overlay could capture every interaction. Adjust the selectors to match the player you are dealing with.

A combined click-to-fix action

If you only want native controls occasionally, bind it to a key instead of running it always. This rule restores controls and clears blocking overlays when you press a shortcut.

document.addEventListener('keydown', function (e) {
  if (e.altKey && e.key.toLowerCase() === 'c') {
    document.querySelectorAll('video').forEach(function (v) {
      v.controls = true;
      v.style.pointerEvents = 'auto';
      v.style.zIndex = '2147483647';
      v.style.position = 'relative';
    });
  }
}, true);

Raising the z-index lifts the video above any overlay so its own control bar receives clicks.

Practical notes

Find a packaged version in our ready-made examples or download JustZix. To go further with speed, read control video playback speed anywhere.

Rate this post

No ratings yet — be the first.

Try it yourself

Install JustZix and paste any snippet from this article. Two minutes from zero to a working rule across all your devices.

Get JustZix

Features · How it works · Examples · Use cases