Javascript Icon Get 67% off the JavaScript Master Bundle!

See the bundle then add to cart and your discount is applied.

0 days
00 hours
00 mins
00 secs

Hacking the HTML5 video element with Suave.js

Suave, for elegant HTML5 videos (how they should have been). Suave was built to re-engineer the unstructured mess the HTML5

HTML5 video is awesome, what’s not awesome is the markup. The semantics and unmodular approach with HTML5 video upset me and I was inspired to fix it. So here’s my idea, which is very modular and works in all browsers supporting HTML5 video.

Table of contents

The problem

HTML5 video is a brilliant invention, cleverly injecting useful pieces of Shadow DOM in for us so we no longer need to code in video controls and other funky buttons. It seems someone had a little too much coffee when thinking about a solution for the markup (don’t get me started on the responsive images element). Why must we configure (manually) a video, what if there are a vast amount of videos on the page?

For those wondering what I’m really digging into, let’s take a cross-browser

  <source src="video/trailer.mp4" type="video/mp4">
  <source src="video/trailer.ogv" type="video/ogv">
  <source src="video/trailer.webm" type="video/webm">

I love the naming conventions here, source ‘src’. Source source (they definitely had too much coffee by this point). But seriously, what on earth happened here? HTML5 is meant to be intelligent and in my eyes this is a little dumb. What happens if I suddenly change the file name and/or directories, I’ve then got to change it multiple times… Crazy.

My solution

So here’s where Suave comes in. Thanks to my little script, you no longer have to worry about the above catastrophe and can code an HTML5 video with just one line of code (this is proper valid HTML5, too!):

<video data-src="video/mymovie.{mp4, ogv, webm}"></video>

All you need to do is feed it the file extensions you require for each video inside a data-* attribute, easy. Suave is fully modular as well, call it as many times on the page and it’ll just keep doing its thing. What I also like about this solution is that I’m enhancing HTML5, with HTML5. Of course some people will disagree and say I’m missing a few codecs, lost my mind and am hashing out strange ideas, but my project would be finished ontime and save countless future hours.

JavaScript Array Methods eBook Cover

🎉 Download it free!

Ready to go beyond ForEach? Get confident with advanced methods - Reduce, Find, Filter, Every, Some and Map.

  • Green Tick Icon Fully understand how to manage JavaScript Data Structures with immutable operations
  • Green Tick Icon 31 pages of deep-dive syntax, real-world examples, tips and tricks
  • Green Tick Icon Write cleaner and better-structured programming logic within 3 hours

As an extra bonus, we'll also send you some extra goodies across a few extra emails.

I’ve been using Grunt.js a lot recently and I love how you can simply include some curly braces to say ‘or this too’, so that’s where the idea came from to simplify an overcomplicated system. This is fully semantic stuff too, if anything this improves the semantics of the

<video src="video/mymovie.mp4"></video>

And that’s where the simplicity of my idea came from. Sure it isn’t how the HTML5 spec intended it, but remember this stuff is still new to everyone and remember this is still a huge work in progress.


For those interested in how Suave works, here’s a break down of the script:

window.suave = ( function ( window, document, undefined ) {

  'use strict';

   * Constructor function
  var Suave = function ( elem ) {
    this.elem = elem;

   * Prototypal setup
  Suave.prototype = {

    init : function () {

      var dataAttr = this.elem.getAttribute('data-src');
      var videoSource = dataAttr.match(/^([^]+){/)[1];
      var fileExts = dataAttr.match(/{([^]+)}$/)[1].toString().replace(/\s/g, '').split(',');

      for (var i = 0; i < fileExts.length; i++) {
        var extension = fileExts[i];
        var source = document.createElement('source');
        source.src = videoSource + extension;
        source.type = 'video/' + extension;



   * Initiate the plugin
  []'video[data-src]'), function (suave) {
    new Suave(suave).init();

})( window, document );

From the top, I create the constructor function, which I pass the current element into (passed in at the bottom loop). This then has some internal Prototype workings that grab the data-src attribute (we’re looking at the init function here).

First I grab the videoSource from the attribute, which uses a RegExp to capture the file path and file name, but not the extension.

Next I grab the file extensions (fileExts) which captures everything inside the curlies {}. From here, I use the .toString() method, which converts the array sent back from .match() to a string (you guessed it), from here, I .replace() any whitespace to get a clean array for adding the file extensions, and then use the .split(‘,’) method to split the string by commas which then returns a new array. I then loop through that array of file extensions and create the right amount of tags, populating them with the necessary src and type attributes.

At the bottom, I then hook into the Array.prototype (but use an empty array shorthand to access this) and loop through all video[data-src] tags, which will hold our Suave.js videos! Inside this loop, I pass in the current element and create a new Suave instance to the current item.

Feedback welcome :)

Free eBooks:

JavaScript Array Methods eBook Cover

Ready to go beyond ForEach? Get confident with advanced methods - Reduce, Find, Filter, Every, Some and Map.

NestJS Build a RESTful CRUD API eBook Cover

Build your first NestJS app. With the CLI you'll learn the basics of real-world NestJS development.