Using Twitter Bootstrap 3.0, I wanted to use its modal window to open YouTube videos.
Rather than manually placing the HTML for each video’s modal, or creating a line of JavaScript for each separate video, I wanted any YouTube link to automatically pop up embedded in a modal window, without extra code. The modal is a progressive enhancement. The link should work normally without any JavaScript. You could also disable the modal functionality for small devices on a responsive design.
Let’s say I have a link on the page in one of the following formats:
In order to generate an iframe embed code, we’ll first need to get the video ID from the URL. Then, put this video ID into the iframe embed format that YouTube gives you under “Share”, and open that in a modal. I’ve added the data-width
and data-height
attributes, which will be used to determine the size of the modal window and embed. If these are not set, a default size will be used.
Modal HTML
I’m going to use empty modal HTML that’s placed right before the closing body tag, rather than using an external page. Note the ID, “mediaModal”, which will be used in the JavaScript. This is the basic modal template provided on the official Bootstrap 3.0 docs.
This only needs to be included on the page once, as multiple videos will open in this same modal container:
jQuery – Open all YouTube video links in a modal window
Explanation
First we find all links that begin with http://www.youtube.com, using the attribute-starts-with selector. Then we need to get the video ID from the video URL. I decided to use the plugin on GitHub “jQuery Query Parser” (open source MIT license), to parse out the query string variables and their values. This makes it a little more future-proof, as it will better handle URLs that contain more parameters (HD, rel=0, etc) and malformed links. The minified version of this plugin is pretty small.
The script then goes and inserts the YouTube iframe HTML into the contents of .modal-body
inside of #mediaModal
. If you use the data-height and data-width, they’re used in the embed, else it defaults to 560×315.
Twitter bootstrap’s modal window is a little limited, compared to some lightboxes. It will not dynamically size itself to fit the content, though you can have it be a percentage width via CSS for responsive sites. In this case, I’d like the window to be just big enough for the video, so that requires calculating a few widths.
The .modal-body
and .modal-dialog
elements both default to having padding, that could be modified in your CSS. So the script adds the left and right padding of both, to the width of the video, in order to get the final width that the .modal-dialog
container should be. This is hooked into the show.bs.modal
event.
Then finally, the modal window is opened with modal()
.
Note: Bad NPObject? Blocked a frame with origin?
If the iframe code that isn’t being inserted into the DOM does not include &wmode=transparent on the src link (it does in the above example), you may start getting these errors:
- Chrome: Blocked a frame with origin “http://www.youtube.com” from accessing a frame with origin
- Firefox: Error bad NPObject
This caused a lot of frustrations, because everything online was saying that this was a cross-domain issue or a browser bug, etc. The video would work in Chrome, but would be black and not work in Firefox. Hopefully that helps if you’re struggling with the same issue! Note that Chrome will still give an origin error from within the frame which will not stop JS processing on your page, and appears to be a bug in Chrome that isn’t fixed yet (per some StackOverflow posts). The video still plays and operates fine.
This is pretty great.. thank you for sharing.
I have a question though. *I’m a novice with JQuery and JavaScript*
I have around 20 unique modals (bootstrap 3) on my site. Each modal has a unique youtube video embedded in it. To do this for my site, do you recommend I script this JQuery 20 different times, each with the appropriate corresponding Modal ID?
Thanks so much..
Justin
I wrote this script to avoid and replace the type of situation you are describing, where there are 20+ unique modal IDs. I try to stick to the DRY principle (Don’t Repeat Yourself). It only requires the single “Video / Generic Modal” HTML, and then the embed code is dynamically inserted into that. If the modals are only for video (no other content), then this script could be used to replace all of those.
Do you have a link showing this in action? I think its what I want, but would like to eyeball it. Thanks.
EDIT: A demo is now available on CodePen http://codepen.io/forthewinn/pen/bNXNGK
“&wmode=transparent” is PURE GOLD! Thanks man!!
For a responsive modal that automatically sizes the modal to fit the current display, change these three lines:
…to this:
I wanted to submit this to the gist repo, but couldn't find a way to do so.
Great. Thanks for sharing.
I think it’d be a good idea to add a max width too, so the video does not get too huge/stretched for giant monitors (or else a max-width may be on the modal itself).
Thanks a lot. Useful Code 🙂
Thanks, helped me with my Bandspage! But I don’t like your approach on using the jQuery Parser, I just did:
var queryStringArray = queryString.split("&");
var queryVars = new Array();
for(i = 0; i < queryStringArray.length; i++) {
queryVars[queryStringArray[i].split("=")[0]] = queryStringArray[i].split("=")[1];
}
Results in one less dependency.
Cheers, Gregor from My Friend The Immigrant
Weird, embedded Gist’s don’t show up in Chrome on Mac…
Refused to execute script from 'https://gist.github.com/cf4add71f2d3e138cdd3.js?file=' because its MIME type ('text/html') is not executable, and strict MIME type checking is enabled. www.joshuawinn.com/:1
Refused to execute script from 'https://gist.github.com/0e936461be263d7e7474.js?file=' because its MIME type ('text/html') is not executable, and strict MIME type checking is enabled. www.joshuawinn.com/:1
Refused to execute script from 'https://gist.github.com/6655039.js?file=' because its MIME type ('text/html') is not executable, and strict MIME type checking is enabled. www.joshuawinn.com/:1
Odd..are you still receiving this error? I saw a few issues about this online related to the nosniff header and RAW.github.com, but this really shouldn’t be happening with GIST.github.com’s embed, unless its a problem with the plugin that displays it. I hope it was a temporary issue.
Briliiant! Looks like there is a problem when you use the https. It will not load on the modal. Would you know how to fix it?
@Tony, just remove the http:// part from line 8 in the JavaScript code.
@Tony, my last comment was incorrect. Replace line 8 with this:
$('a[href^="http://www.youtube.com"], [href^="https://www.youtube.com"]').on('click', function(e){
Hi there,
Thank you so much for this. It’s really nifty. I was trying to get this to work with a vimeo video embed but it doesn’t seem to be working. Here is the code I am using
$(document).ready(function(){
// BOOTSTRAP 3.0 – Open Vimeo Video Dynamicaly in Modal Window
// Modal Window for dynamically opening videos
$(‘a[href^=”https://www.vimeo.com”]’).on(‘click’, function(e){
// Store the query string variables and values
// Uses “jQuery Query Parser” plugin, to allow for various URL formats (could have extra parameters)
var queryString = $(this).attr(‘href’).slice( $(this).attr(‘href’).indexOf(‘?’) + 1);
var queryVars = $.parseQuery( queryString );
// if GET variable “v” exists. This is the Vimeo Video ID
if ( ‘v’ in queryVars )
{
// Prevent opening of external page
e.preventDefault();
// Variables for iFrame code. Width and height from data attributes, else use default.
var vidWidth = 560; // default
var vidHeight = 315; // default
if ( $(this).attr(‘data-width’) ) { vidWidth = parseInt($(this).attr(‘data-width’)); }
if ( $(this).attr(‘data-height’) ) { vidHeight = parseInt($(this).attr(‘data-height’)); }
var iFrameCode = ”;
// Replace Modal HTML with iFrame Embed
$(‘#mediaModal .modal-body’).html(iFrameCode);
// Set new width of modal window, based on dynamic video content
$(‘#mediaModal’).on(‘show.bs.modal’, function () {
// Add video width to left and right padding, to get new width of modal window
var modalBody = $(this).find(‘.modal-body’);
var modalDialog = $(this).find(‘.modal-dialog’);
var newModalWidth = vidWidth + parseInt(modalBody.css(“padding-left”)) + parseInt(modalBody.css(“padding-right”));
newModalWidth += parseInt(modalDialog.css(“padding-left”)) + parseInt(modalDialog.css(“padding-right”));
newModalWidth += ‘px’;
// Set width of modal (Bootstrap 3.0)
$(this).find(‘.modal-dialog’).css(‘width’, newModalWidth);
});
// Open Modal
$(‘#mediaModal’).modal();
}
});
// Clear modal contents on close.
// There was mention of videos that kept playing in the background.
$(‘#mediaModal’).on(‘hidden.bs.modal’, function () {
$(‘#mediaModal .modal-body’).html(”);
});
});
There is no “v” in the query string used in Vimeo videos. This would need to be changed to use the Vimeo URL format, which appears to be a number after vimeo.com. And the embed code would need to change.
Does anyone have a link where this was implemented and can be seen in action? I had a tough time trying to get this to work properly (http://lab.abhinayrathore.com/bootstrap-youtube/).
I’ve created a CodePen demo: http://codepen.io/forthewinn/pen/bNXNGK
how can this be implemented on images? i set up everything but somehow my image link goes straight to the YouTube page, no modal window.
This isn’t really intended for images. You could check the file extension on the link and do something different if it’s an image.
That’s a really cool solution, definitely gonna use it in my next bootstrap projects instead of implementing third party lightbox that supports video. Thanks for sharing!
how do you disable the modal functionality on small devices?
You could check the window width with
$(window).width()
.Hi Josh
Precisely the idea I was looking for. I would like to know if I could follow the same script in opening up a Contact Form within the modal body, remotely?
I’m very new to this and would like a little more explanation if possible.
1. Is all of this code on the html page, or do these need to be on seperate files of some kind?
2. In the jquery portion you wrote
// REQUIRED: Include “jQuery Query Parser” plugin here or before this point:
// https://github.com/mattsnider/jquery-plugin-query-parser
how is this done?
Thanks.
The minified version of the jQuery Query Parser is included on the CodePen right under that comment; I’ve updated the comment on there to make it more clear. You could either do the same, or include the file itself (from https://github.com/mattsnider/jquery-plugin-query-parser/blob/master/jquery-queryParser.min.js).
Thanks for replying but I am still unsure how to actually include the parser. What do I download, where do I put it, or do I copy it and paste it somewhere? 😛 Thanks again.
Please answer, I have the exact same question and I’m tearing my hair out over it.
The answer is in the comment above: http://www.joshuawinn.com/opening-youtube-links-dynamically-in-a-twitter-bootstrap-modal-window/#comment-94919
View the CodePen demo: http://codepen.io/forthewinn/pen/bNXNGK
I finally got it to work! Could someone please tell me how to make the youtube video autoplay in this code? thanks.
I would also like a way to set autoplay. Adding it as a querystring doesn’t work
https://www.youtube.com/watch?v=VIDID?autoplay=1&rel=0&enablejsapi=1&playerapiid=ytplayer"
You have two question marks there in the URL. Try with an ampersand after the video ID?