Welcome folks today in this blog post we will be making a youtube videos gallery and embed videos in gallery in browser using localstorage api in html5 css3 and javascript. All the full source code of the application is shown below.
Get Started
In order to get started you need to make an index.html
file and copy paste the following code
index.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta http-equiv="X-UA-Compatible" content="ie=edge" /> <title>My YouTube Resource Gallery</title> <link rel="stylesheet" href="app.css" /> </head> <body> <div class="container"> <div class="header"> <div> <h1 class="headline">My YouTube Resource Gallery</h1> <p>The perfect app to keep track of valuable resources while learning to code. As you come across a helpful video, add the id here.</p> </div> <form > <label for="videoId">Video Id</label> <input type="text" name="videoId" id="videoId" placeholder="HSN345J9J"> <button onclick="saveVideo(event)">Save the Video</button> </form> </div> <ul id="videosContainer"> </div> </div> <div id="popup" onclick="handlePopupClick()" class="closed"> <iframe width="560" height="315" frame-border="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen ></iframe> </div> <script src="app.js"></script> </body> </html> |
Here we have html code in which we have the input field where the user can save the video by providing the youtube url. And also we have the button save video to actually save the video in the form of gallery.
Then we will have the videos listed in the form of gallery. If you click an individual video then popup window will appear where you can play the youtube video with the actual controls.
Styling the App
Now we will add styling to this application by providing the custom styles which are as follows
app.css
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 |
/* global stuff */ :root { --background: #232946; --headline: #fffffe; --copy: #b8c1ec; --accent: #eebbc3; --accent-text: #232946; } body { font-family: sans-serif; background-color: var(--background); } *{ box-sizing: border-box; } p, label { color: var(--copy); font-size: 18px; letter-spacing: 1.5px; line-height: 34px } .container { max-width:1000px; margin: 0 auto; padding:30px } /* header */ .header { display: grid; grid-template-columns: 1fr 1fr; align-items: center; gap: 40px; margin-top: 60px; } h1.headline { color: var(--headline); font-size: 54px; margin-bottom: 2px; } @media only screen and (max-width: 800px) { .header { display: block; } } /* forms */ label { display: block; margin-bottom: 5px; } input { padding: 20px 15px; width: 100%; border: none; border-radius: 3px; font-size: 18px; } form button { margin-top: 10px; padding: 20px; border-radius: 3px; font-weight: bold; background-color: var(--accent); color: var(--accent-text); border: none; font-size: 18px; cursor: pointer; width:100% } /* videos */ #videosContainer { display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr) ); gap: 10px; list-style-type: none; padding-left: 0; margin-top: 60px; } #videosContainer > li { overflow:hidden; border-radius: 10px; position: relative; } .delete-btn { position: absolute; top: 2px; right: 2px; border: none; border-radius: 100%; font-size: 20px; cursor: pointer; } #videosContainer .thumbnail { border-radius: 10px; width: 100%; transition: transform 250ms; cursor: pointer; } #videosContainer .thumbnail:hover { transform: scale(1.2); } /* popup */ #popup { position: fixed; top: 0; right: 0; bottom: 0; left: 0; display: flex; justify-content: center; align-items: center; background: rgba(20, 20, 20, 0.95); padding: 40px; transition: all 300ms; } iframe { width: 100%; height: auto; max-width: 800px; aspect-ratio: 16 / 9; background: rgb(20, 20, 20); } #popup.open { transform: translateY(0); opacity: 1; } #popup.closed { transform: translateY(-100vh); opacity:0; } |
Now if you open the application basically the app will look like this in the form of interface
Javascript Code
Now we will use localstorage web storage api to store all the videos locally in the form of gallery. First of all we will get all the references of the DOM Elements as shown below. Create an app.js
file and copy paste the below code
app.js
1 2 3 4 5 6 |
const videosContainer = document.getElementById('videosContainer'); const popup = document.getElementById('popup'); const video = document.querySelector('#popup > iframe'); const videoIdInput = document.getElementById('url'); const IDS_KEY = 'youTubeVideoIds'; let youTubeVideoIds = []; |
Here also in this block of code we are declaring an empty array where we will store the urls of all the youtube videos which will be shown in the form of gallery. And also we are declaring a key variable for localstorage which will hold all the youtube videos in localstorage.
1 2 3 4 5 |
const loadVideos = () => { youTubeVideoIds = JSON.parse(localStorage.getItem(IDS_KEY)) || []; }; loadVideos(); |
And now inside this block of code we are executing the loadvideos function at the starting of the app. In loadvideos function we are fetching all the videos which are stored inside the localstorage by using the getItem() Method. Inside this method we are providing the key argument to fetch all the videos stored. If no videos are present then we are initializing an empty array.
Button OnClick function to Save Videos in Gallery
Now we will be writing the function code when we click the save video button. Here we will be fetching the videos from the url. And we will find the videoId from the url. For this we have written the custom function. And after that we are adding the video inside the array and also updating the localstorage api.
1 2 3 4 5 6 7 8 |
const saveVideo = (e) => { e.preventDefault(); const videoId = YouTubeGetID(videoIdInput.value); videoIdInput.value = ''; youTubeVideoIds.unshift(videoId); localStorage.setItem(IDS_KEY, JSON.stringify(youTubeVideoIds)); displayVideos(); }; |
And also we need to define the method YoutubeGetID() Where we will pass the youtube video url to fetch the video id. This function is defined as follows
1 2 3 4 |
function YouTubeGetID(url){ url = url.split(/(vi\/|v=|\/v\/|youtu\.be\/|\/embed\/)/); return (url[2] !== undefined) ? url[2].split(/[^0-9a-z_\-]/i)[0] : url[0]; } |
Here we are using some regular expression to fetch the video id from the youtube video url. And lastly we are returning the youtube video id from this function.
After that guys we also need to define the displayVideos()
function to display all the videos which are present inside the localstorage api. Here we will be using the map
method of arrays to display all the videos which are done as follows
1 2 3 4 5 6 7 8 9 10 11 12 13 |
const displayVideos = () => { const videosStr = youTubeVideoIds .map( (id) => ` <li onclick="clickVideo(event, '${id}')"> <img class="thumbnail" src="https://i3.ytimg.com/vi/${id}/sddefault.jpg" alt="Cover image for YouTube video with id ${id}"> <button class="delete-btn" >×</button> </li> ` ) .join(''); videosContainer.innerHTML = videosStr; }; |
Here guys as you can see we are adding the dynamic html of every video here inside this map function for each video we are having the li
tag inside that we have binded a onclick event listener. When you click on individual video then popup window will appear where the video can be played in a video player. For that we need to make that custom function which is ClickVideo here in this function we will pass the event object and also the actual id of the li which is clicked. And also we have the img tag as well which represents the thumbnail of the youtube video which is shown to the user. And lastly we have the button to actually delete the video from the localstorage.
Now we will define the ClickVideo() function in the below code
1 2 3 4 5 6 7 8 9 10 11 |
const clickVideo = (event, id) => { if (event?.target?.classList?.contains('delete-btn')) { youTubeVideoIds = youTubeVideoIds.filter((i) => i !== id); localStorage.setItem(IDS_KEY, JSON.stringify(youTubeVideoIds)); displayVideos(); } else { video.src = `https://www.youtube.com/embed/${id}`; popup.classList.add('open'); popup.classList.remove('closed'); } }; |
Here guys we are comparing the events inside the if condition to check whether the closed button was clicked or the actual thumbnail was clicked. If the closed button was clicked then we need to remove the video from the array and also update the localstorage api. And again render out all the videos. In the else block we are basically adding a dynamic class to the video element so that it opens inside a popup window where the user can play the video in video player.
As you can see in the above screenshot this is the actual popup window where the video is displayed. And when we try to click outside of the popup window it should close. Basically inside this popup window we are rendering an iframe providing the url of the video with custom width and height and the actual video controls. And also we have given the onclick event listener to it also. As when we click outside the popup window it should close. The function is as follows
1 2 3 4 |
const handlePopupClick = () => { popup.classList.add('closed'); popup.classList.remove('open'); }; |
Here we are adding the close
class and removing the open
class from the popup
element inside this function
Full Javascript Code
Wrapping it all Now see the entire javascript code for the application which are as follows
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
const videosContainer = document.getElementById('videosContainer'); const popup = document.getElementById('popup'); const video = document.querySelector('#popup > iframe'); const videoIdInput = document.getElementById('url'); const IDS_KEY = 'youTubeVideoIds'; let youTubeVideoIds = []; const loadVideos = () => { youTubeVideoIds = JSON.parse(localStorage.getItem(IDS_KEY)) || []; }; const displayVideos = () => { const videosStr = youTubeVideoIds .map( (id) => ` <li onclick="clickVideo(event, '${id}')"> <img class="thumbnail" src="https://i3.ytimg.com/vi/${id}/sddefault.jpg" alt="Cover image for YouTube video with id ${id}"> <button class="delete-btn" >×</button> </li> ` ) .join(''); videosContainer.innerHTML = videosStr; }; const clickVideo = (event, id) => { if (event?.target?.classList?.contains('delete-btn')) { youTubeVideoIds = youTubeVideoIds.filter((i) => i !== id); localStorage.setItem(IDS_KEY, JSON.stringify(youTubeVideoIds)); displayVideos(); } else { video.src = `https://www.youtube.com/embed/${id}`; popup.classList.add('open'); popup.classList.remove('closed'); } }; const handlePopupClick = () => { popup.classList.add('closed'); popup.classList.remove('open'); }; const saveVideo = (e) => { e.preventDefault(); const videoId = YouTubeGetID(videoIdInput.value); videoIdInput.value = ''; youTubeVideoIds.unshift(videoId); localStorage.setItem(IDS_KEY, JSON.stringify(youTubeVideoIds)); displayVideos(); }; function YouTubeGetID(url){ url = url.split(/(vi\/|v=|\/v\/|youtu\.be\/|\/embed\/)/); return (url[2] !== undefined) ? url[2].split(/[^0-9a-z_\-]/i)[0] : url[0]; } loadVideos(); displayVideos(); |