49

I'm trying to get the video to be able to play and pause like it does YouTube (Using both the play and pause button, and clicking the video itself.)

<video width="600" height="409" id="videoPlayer" controls="controls">
 <!-- MP4 Video -->
 <source src="video.mp4" type="video/mp4">
</video>


<script>
    var videoPlayer = document.getElementById('videoPlayer');

    // Auto play, half volume.
    videoPlayer.play()
    videoPlayer.volume = 0.5;

    // Play / pause.
    videoPlayer.addEventListener('click', function () {
        if (videoPlayer.paused == false) {
            videoPlayer.pause();
            videoPlayer.firstChild.nodeValue = 'Play';
        } else {
            videoPlayer.play();
            videoPlayer.firstChild.nodeValue = 'Pause';
        }
    });
</script>

Do you have any ideas why this would break the play and pause control button?

Peter Badida
  • 11,310
  • 10
  • 44
  • 90
user2698522
  • 491
  • 1
  • 4
  • 4
  • 1
    possible duplicate of [Click the poster image the HTML5 video plays?](http://stackoverflow.com/questions/5278262/click-the-poster-image-the-html5-video-plays) – Daniel Golden Jan 29 '15 at 16:22
  • Keep in mind that the latest firefox versions have out-of-the-box support for pausing/playing the video on click on a `` tag. – ccpizza Sep 22 '17 at 23:02
  • you need not added controls it comes as part of the tag itself. – Nagappan Feb 05 '19 at 14:32

11 Answers11

120

The simplest form is to use the onclick listener:

<video height="auto" controls="controls" preload="none" onclick="this.play()">
 <source type="video/mp4" src="vid.mp4">
</video>

No jQuery or complicated Javascript code needed.

Play/Pause can be done with onclick="this.paused ? this.play() : this.pause();".

To keep it from clashing with the video controls on some browsers, call preventDefault on the click event:

onclick="this.paused ? this.play() : this.pause(); arguments[0].preventDefault();"

Demo:

<video height="200" controls="controls" preload="none" onclick="this.play();arguments[0].preventDefault();">
 <source type="video/webm" src="https://upload.wikimedia.org/wikipedia/commons/transcoded/5/54/Yawning_kitten.ogv/Yawning_kitten.ogv.480p.vp9.webm">
</video>
BadFeelingAboutThis
  • 14,445
  • 2
  • 33
  • 40
dev4life
  • 10,785
  • 6
  • 60
  • 73
  • 3
    This answer should be accepted as correct, because it is the most simple and doesn't break controls behavior. – Maxim Khan-Magomedov Apr 26 '16 at 10:54
  • 11
    Combine this with the `this.paused?this.play():this.pause()` logic in John's answer and you've got a winner. – intcreator May 12 '16 at 20:17
  • 3
    This does not work in Safari, at least if you have a poster image. Not sure if there is no poster image if it would work. – Lisa May 21 '18 at 05:44
  • Just add a preventDefault on the event to keep the video onclick from clashing with the controls click. `onclick="this.paused ? this.play() : this.pause(); arguments[0].preventDefault();"` – BadFeelingAboutThis Mar 30 '23 at 18:08
50

HTML:

<video class="video"><source src=""></video>

JAVASCRIPT: "JQUERY"

$('.video').click(function(){this.paused?this.play():this.pause();});
Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
Mickey
  • 2,285
  • 6
  • 26
  • 37
16

Adding return false; worked for me:

jQuery version:

$(document).on('click', '#video-id', function (e) {
    var video = $(this).get(0);
    if (video.paused === false) {
        video.pause();
    } else {
        video.play();
    }

    return false;
});

Vanilla JavaScript version:

var v = document.getElementById('videoid');
v.addEventListener(
    'play', 
    function() { 
        v.play();
    }, 
    false);

v.onclick = function() {
    if (v.paused) {
        v.play();
    } else {
        v.pause();
    }

    return false;
};
Roberts126
  • 249
  • 3
  • 4
4

I had this same problem and solved it by adding an event handler for the play action in addition to the click action. I hide the controls while playing to avoid the pause button issue.

    var v = document.getElementById('videoID');
    v.addEventListener(
       'play', 
          function() { 
             v.play();
          }, 
        false);

    v.onclick = function() {
      if (v.paused) {
        v.play();
        v.controls=null;
      } else {
        v.pause();
        v.controls="controls";
      }
    };

Seeking still acts funny though, but at least the confusion with the play control is gone. Hope this helps.

Anyone have a solution to that?

jkrz
  • 41
  • 3
4

I had countless issues doing this but finally came up with a solution that works.

Basically the code below is adding a click handler to the video but ignoring all the clicks on the lower part (0.82 is arbitrary but seems to work on all sizes).

    $("video").click(function(e){

        // get click position 
        var clickY = (e.pageY - $(this).offset().top);
        var height = parseFloat( $(this).height() );

        // avoids interference with controls
        if(y > 0.82*height) return;

        // toggles play / pause
        this.paused ? this.play() : this.pause();

    });
ios-lizard
  • 834
  • 1
  • 12
  • 19
2

Following up on ios-lizard's idea:

I found out that the controls on the video are about 35 pixels. This is what I did:

$(this).on("click", function(event) {
    console.log("clicked");
    var offset = $(this).offset();
    var height = $(this).height();
    var y = (event.pageY - offset.top - height) * -1;
    if (y > 35) {
        this.paused ? this.play() : this.pause();
    }
});

Basically, it finds the position of the click relative to the element. I multiplied it by -1 to make it positive. If the value was greater than 35 (the height of the controls) that means that the user click somewhere else than the controls Therefore we pause or play the video.

KatieK
  • 13,586
  • 17
  • 76
  • 90
Nathan
  • 1,321
  • 1
  • 18
  • 32
2

How about this one

<video class="play-video" muted onclick="this.paused?this.play():this.pause();">
   <source src="" type="video/mp4">
</video>
Abhi Burk
  • 2,003
  • 1
  • 14
  • 21
2

On Chromium 89 and Firefox 86 click on body works, except the first click of preload="none" for Chromium

Of those browsers:

  • Firefox works perfectly: all clicks on video body toggle play/pause, just like corresponding clicks on controls. Furthermore it shows an intuitive placeholder that makes it clear to the user that clicking will work:

    enter image description here

  • Chromium has a bug where the first click no video body does not work for videos that have preload="none". Further clicks work however.

    And its placeholder does not make it clear that you can click to play anywhere (which you can't anyways, hopefully they will add a decent placeholder when the bug gets fixed):

    enter image description here

Therefore, the best option is to work around that bug minimally by only doing play on the first click:

<!doctype html>
<html lang=en>
<head>
<meta charset=utf-8>
<title>Min</title>
</head>
<body>
<video id="vid" height="200" controls="controls" preload="none">
 <source type="video/webm" src="https://upload.wikimedia.org/wikipedia/commons/transcoded/5/54/Yawning_kitten.ogv/Yawning_kitten.ogv.480p.vp9.webm">
</video>
<script>
let first = true;
document.getElementById('vid').addEventListener('click', (e) => {
  if (first) {
    e.target.play();
  }
  first = false;
});
</script>
</body>
</html>

This also does not break Firefox' correct behavior in any way.

TODO: make that workaround perfect by adding an overlay div that clearly indicates that the initial click to play will work, e.g. along the lines of: https://codepen.io/wizaRd_Mockingjay/pen/NVGpep but keeping the controls.

The JavaScript solution shown at: https://stackoverflow.com/a/35563612/895245 of doing onclick="this.play()" actually breaks the play after the first play + pause from working on those browsers, so I do not recommend it.

The evil part in me wants to think that Chromium behavior is worse because YouTube videos are the only videos that matter to them >:-)

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
  • Hi, some how when i remove controls attribute then onclick="this.paused ? this.play() : this.pause();" works fine but when it adds controls to shadow dom, chrome messes up the click on video and end up clicking somewhere in shadow dom and due to that it causes a bug. – Shashank Bhatt Mar 17 '22 at 11:23
1

The problem appears to be internal bubbling within the <video> element ... so when you click on the "Play" button the code triggers and then the play button itself get triggered :(

I couldn't find a simple (reliable) way to stop the click bubbling through (logic tells me there should be a way, but... it escapes me right now)

Anyway, the solution I found to this was to put a transparent <div> over the video sized to fit down to where the controls appear... so if you click on the div then your script controls play/pause but if the user clicks on the controls themselves then the <video> element handles that for you.

The sample below was sized for my video so you may need to juggle sizes of the relative <div>s but it should get you started

<div id="vOverlay" style="position:relative; width:600px; height:300px; z-index:2;"></div>
<video style="position:relative; top:-300px; z-index:1;width:600px;height:340px;" width="600" height="409" id=videoPlayer controls="controls">
<source src="video.mp4" type="video/mp4">
</video>

<script>
    var v = document.getElementById('videoPlayer');
    var vv = document.getElementById('vOverlay');
    <!-- Auto play, Half volume -->
    v.play()
    v.volume = 0.5;
    v.firstChild.nodeValue = "Play";

    <!-- Play, Pause -->
    vv.addEventListener('click',function(e){
        if (!v.paused) {
            console.log("pause playback");
            v.pause();
            v.firstChild.nodeValue = 'Pause';
        } else {
            console.log("start playback")
            v.play();
            v.firstChild.nodeValue = 'Play';
        }
      });
</script>
Offbeatmammal
  • 7,970
  • 2
  • 33
  • 52
0

must separate this code to work well, or it well pause and play in one click !

 $('video').click(function(){this.played ? this.pause() ;});
  $('video').click(function(){this.paused ? this.play() ;});
0

For chrome as of now we can fix the native click on video on shadow elements by this lines.

video::-webkit-media-controls {
    pointer-events: none;
}

But due to this native controls stops working and then we have to even enable that pointer events on inner sub-tree for enabling volume, seekbar and fullscreen controls by setting it to auto.

video::-webkit-media-controls-timeline {
    pointer-events: auto
}

video::-webkit-media-controls-play-button {
    pointer-events: auto;
}

And then either as per above answer from ciro or oabarca, we can make a click on parent div or on the video itself and then it will work fine.

Shashank Bhatt
  • 717
  • 1
  • 11
  • 28