DEV Community

loading...
Cover image for How to create Disney plus clone with pure HTML, CSS, JS

How to create Disney plus clone with pure HTML, CSS, JS

Modern Web
Hello, I am kunaal a fullstack developer.I have a youtube channel "Modern Web" where I teach to make awesome web UI/ UX. Don't forget to checkout my youtube channel
・9 min read

Hello, Today we'll see, how we can easily create a disney plus UI clone using HTML, CSS and JS only. No other library. We'll also see how we can make an endless slider effect. Which took me 2-3 hrs to code.

Our clone is very similar to the original disney plus website. It is only one page(homepage) website. It has navbar and search box with cool click effect same as disney+ and it also has a slider or carousel with infinity or endless effect. Which was very hard for me to make at first. And after that we also have movie cards. With awesome card hover effect. And we have much more.

To see demo or you want full coding tutorial video with explanation. You can watch the tutorial below.

Video Tutorial

I appreciate if you can support me by subscribing my youtube channel.

So, without wasting more time let's see how to code this.

Code

Before we start writing our code. Although it's not a Node app but we should see it folder structure at least to with.

Frame 7

Download Template

You can see we have a file named data.js. This file contain our movie slider data. You can see below.

let movies = [
    {
        name: 'falcon and the winter soldier',
        des: 'Lorem ipsum dolor sit amet consectetur adipisicing elit. Velit porro et veniam excepturi, eaque voluptatem impedit nulla laboriosam facilis ut laboriosam libero!',
        image: 'images/slider 2.PNG'
    },
    {
        name: 'loki',
        des: 'Lorem ipsum dolor sit amet consectetur adipisicing elit. Velit porro et veniam excepturi, eaque voluptatem impedit nulla laboriosam facilis ut laboriosam libero!',
        image: 'images/slider 1.PNG'
    },
    {
        name: 'wanda vision',
        des: 'Lorem ipsum dolor sit amet consectetur adipisicing elit. Velit porro et veniam excepturi, eaque voluptatem impedit nulla laboriosam facilis ut laboriosam libero!',
        image: 'images/slider 3.PNG'
    },
/// and so on
]
Enter fullscreen mode Exit fullscreen mode

If you see the starting data. You'll notice that our slide-1 is on second number on the list. Why is that. That is because. Our slider will have 3 slides at a time and we want the active slide to be in center. Which means when we first start with slide data. our active slide or first slide will be in middle. I hope this make sense. If not then watch it video tutorial for more better understanding.

Now let's code the webpage.

Webpage.

Start with index.html. Write basic HTML structure and link CSS and JS files. Make sure you add data.js file before app.js. So that we can access the data in app.js file.

Now first create Navbar.

<nav class="navbar">
    <img src="images/logo.png" class="brand-logo" alt="">
    <ul class="nav-links">
        <li class="nav-items"><a href="#">TV</a></li>
        <li class="nav-items"><a href="#">movies</a></li>
        <li class="nav-items"><a href="#">sports</a></li>
        <li class="nav-items"><a href="#">premium</a></li>
    </ul>

    <div class="right-container">
        <input type="text" class="search-box" placeholder="search">
        <button class="sub-btn">subscribe</button>
        <a href="#" class="login-link">login</a>
    </div>
</nav>
Enter fullscreen mode Exit fullscreen mode
*{
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

body{
    width: 100%;
    background: #0c111b;
    position: relative;
    font-family: roboto, sans-serif;
}

.navbar{
    width: 100%;
    height: 80px;
    position: fixed;
    top: 0;
    left: 0;
    padding: 0 4%;
    background: #0c111b;
    z-index: 9;
    display: flex;
    align-items: center;
}

.brand-logo{
    height: 70px;
}

.nav-links{
    margin-top: 10px;
    display: flex;
    list-style:none;
}

.nav-items a{
    text-decoration: none;
    margin-left: 20px;
    text-transform: capitalize;
    color: #fff;
    opacity: 0.9;
}

.right-container{
    display: block;
    margin-left: auto;
}

.search-box{
    border: none;
    border-bottom: 1px solid #aaa;
    background: transparent;
    outline: none;
    height: 30px;
    color:#fff;
    width: 250px;
    text-transform: capitalize;
    font-size: 16px;
    font-weight: 500;
    transition: .5s;
}

.search-box:focus{
    width: 400px;
    border-color: #1f80e0;
}

.sub-btn{
    background: #1f80e0;
    height: 30px;
    padding: 0 20px;
    color: #fff;
    border-radius: 5px;
    border: none;
    outline: none;
    text-transform: uppercase;
    font-weight: 700;
    font-size: 12px;
    margin: 0 10px;
}

.login-link{
    color: #fff;
    opacity: 0.9;
    text-transform: uppercase;
    font-size: 15px;
    font-weight: 700;
    text-decoration: none;
}
Enter fullscreen mode Exit fullscreen mode
Output

Capture

Now let's make slider. We'll create these slides with JS but for styling purpose just create one for now in HTML.

div class="carousel-container">
    <div class="carousel">
        <div class="slider">
            <div class="slide-content">
                <h1 class="movie-title">loki</h1>
                <p class="movie-des">Lorem ipsum dolor sit, amet consectetur adipisicing elit. Suscipit saepe eius ratione nostrum mollitia explicabo quae nam pariatur. Sint, odit?</p>
            </div>
            <img src="images/slider 1.PNG" alt="">
        </div>
    </div>
</div>
Enter fullscreen mode Exit fullscreen mode
.carousel-container{
    position: relative;
    width: 100%;
    height: 450px;
    padding: 20px 0;
    overflow-x: hidden;
    margin-top: 80px;
}

.carousel{
    display: flex;
    width: 92%;
    height: 100%;
    position: relative;
    margin: auto;
}

.slider{
    flex: 0 0 auto;
    margin-right: 30px;
    position: relative;
    background: rgba(0, 0, 0,0.5);
    border-radius: 5px;
    width: 100%;
    height: 100%;
    left: 0;
    transition: 1s;
    overflow: hidden;
}

.slider img{
    width: 70%;
    min-height: 100%;
    object-fit: cover;
    display: block;
    margin-left: auto;
}

.slide-content{
    position: absolute;
    width: 50%;
    height: 100%;
    z-index: 2;
    background: linear-gradient(to right, #030b17 80%, #0c111b00);
    color: #fff;
}

.movie-title{
    padding-left: 50px;
    text-transform: capitalize;
    margin-top: 80px;
}

.movie-des{
    width: 80%;
    line-height: 30px;
    padding-left: 50px;
    margin-top: 30px;
    opacity: 0.8;
}
Enter fullscreen mode Exit fullscreen mode
Output

Capture2
YOu can comment the slide now. As we are done styling it.
And create this slider working. Watch this to understand the working concept of this slider.

Inside app.js . Select our Carousel element and create an empty array to store all slides.

const carousel = document.querySelector('.carousel');
let sliders = [];

let slideIndex = 0; // to track current slide index.
Enter fullscreen mode Exit fullscreen mode

Now create a function createSlide for creating a slide.

const createSlide = () => {
    if(slideIndex >= movies.length){
        slideIndex = 0;
    }

    // creating DOM element
    let slide = document.createElement('div');
    let imgElement = document.createElement('img');
    let content = document.createElement('div');
    let h1 = document.createElement('h1');
    let p = document.createElement('p');
}
Enter fullscreen mode Exit fullscreen mode

In this function. In the start we are increasing or setting our next slideIndex with some if/else condition. And after that we are creating DOM element that we need for our slide. These all elements are exactly same as we had in our index.html.

After creating all these elements. Append/attach these elements to one another to form the HTML strucuture.

{
    // attaching all elements
    imgElement.appendChild(document.createTextNode(''));
    h1.appendChild(document.createTextNode(movies[slideIndex].name));
    p.appendChild(document.createTextNode(movies[slideIndex].des));
    content.appendChild(h1);
    content.appendChild(p);
    slide.appendChild(content);
    slide.appendChild(imgElement);
    carousel.appendChild(slide);
}
Enter fullscreen mode Exit fullscreen mode

this code is inside createSlide function.

After done appending elements to each other. Now set their class names and set image's source.

{
    // setting up image
    imgElement.src = movies[slideIndex].image;
    slideIndex++;

    // setting elements classname
    slide.className = 'slider';
    content.className = 'slide-content';
    h1.className = 'movie-title';
    p.className = 'movie-des';

    sliders.push(slide);
}
Enter fullscreen mode Exit fullscreen mode

And last remember to push the slide inside sliders array.

We are done creating sliders. But our slider won't work why because we have to shift our first slide to the left. For that add this at the end of the function.

{
    if(sliders.length){
        sliders[0].style.marginLeft = `calc(-${100 * (sliders.length - 2)}% - ${30 * (sliders.length - 2)}px)`;
    }
}
Enter fullscreen mode Exit fullscreen mode

And now if you create slides. You'll see our slider works or not.

for(let i = 0; i < 3; i++){
    createSlide();
}

setInterval(() => {
    createSlide();
}, 3000);
Enter fullscreen mode Exit fullscreen mode

We are done with Sliders. Now create video cards.

<div class="video-card-container">
    <div class="video-card">
        <img src="images/disney.PNG" class="video-card-image" alt="">
        <video src="videos/disney.mp4" mute loop class="card-video"></video>
    </div>
    <div class="video-card">
        <img src="images/pixar.PNG" class="video-card-image" alt="">
        <video src="videos/pixar.mp4" mute loop class="card-video"></video>
    </div>
    <div class="video-card">
        <img src="images/marvel.PNG" class="video-card-image" alt="">
        <video src="videos/marvel.mp4" mute loop class="card-video"></video>
    </div>
    <div class="video-card">
        <img src="images/star-wars.PNG" class="video-card-image" alt="">
        <video src="videos/star-war.mp4" mute loop class="card-video"></video>
    </div>
    <div class="video-card">
        <img src="images/geographic.PNG" class="video-card-image" alt="">
        <video src="videos/geographic.mp4" mute loop class="card-video"></video>
    </div>
</div>
Enter fullscreen mode Exit fullscreen mode
.video-card-container{
    position: relative;
    width: 92%;
    margin: auto;
    height: 10vw;
    display: flex;
    margin-bottom: 20px;
    justify-content: space-between;
}

.video-card{
    position: relative;
    min-width: calc(100%/5 - 10px);
    width: calc(100%/5 - 10px);
    height: 100%;
    border-radius: 5px;
    overflow: hidden;
    background: #030b17;
}

.video-card-image,
.card-video{
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.card-video{
    position: absolute;
}

.video-card:hover .video-card-image{
    display: none;
}
Enter fullscreen mode Exit fullscreen mode
Output

Capture3
And to make video play on hover card. Code this.

/// video cards

const videoCards = [...document.querySelectorAll('.video-card')];

videoCards.forEach(item => {
    item.addEventListener('mouseover', () => {
        let video = item.children[1];
        video.play();
    })
    item.addEventListener('mouseleave', () => {
        let video = item.children[1];
        video.pause();
    })
})
Enter fullscreen mode Exit fullscreen mode

This effect will only work if user click on your site first. If use did not click on your page first then the video will not play because of the google chrome policy.

And the last thing. Let's create cards.

    <h1 class="title">recommended for you</h1>
    <div class="movies-list">
        <button class="pre-btn"><img src="images/pre.png" alt=""></button>
        <button class="nxt-btn"><img src="images/nxt.png" alt=""></button>
        <div class="card-container">
            <div class="card">
                <img src="images/poster 1.png" class="card-img" alt="">
                <div class="card-body">
                    <h2 class="name">movie name</h2>
                    <h6 class="des">Lorem ipsum dolor sit amet consectetur.</h6>
                    <button class="watchlist-btn">add to watchlist</button>
                </div>
            </div> 
            ...20+ more cards
        </div>
   </div>
.. repeat this whole block 3-4 times with different card content
Enter fullscreen mode Exit fullscreen mode
.title{
    color: #fff;
    opacity: 0.9;
    padding-left: 4%;
    text-transform: capitalize;
    font-size: 22px;
    font-weight: 500;
}

.movies-list{
    width: 100%;
    height: 220px;
    position: relative;
    margin: 10px 0 20px;
}

.card-container{
    position: relative;
    width: 92%;
    padding-left: 10px;
    height: 220px;
    display: flex;
    margin: 0 auto;
    align-items: center;
    overflow-x: auto;
    overflow-y: visible;
    scroll-behavior: smooth;
}

.card-container::-webkit-scrollbar{
    display: none;
}

.card{
    position: relative;
    min-width: 150px;
    width: 150px;
    height: 200px;
    border-radius: 5px;
    overflow: hidden;
    margin-right: 10px;
    transition: .5s;
}

.card-img{
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.card:hover{
    transform: scale(1.1);
}

.card:hover .card-body{
    opacity: 1;
}

.card-body{
    opacity: 0;
    width: 100%;
    height: 100%;
    position: absolute;
    top: 0;
    left: 0;
    z-index: 2;
    background: linear-gradient(to bottom, rgba(4, 8, 15, 0), #192133 90%);
    padding: 10px;
    transition: 0.5s;
}

.name{
    color: #fff;
    font-size: 15px;
    font-weight: 500;
    text-transform: capitalize;
    margin-top: 60%;
}

.des{
    color: #fff;
    opacity: 0.8;
    margin: 5px 0;
    font-weight: 500;
    font-size: 12px;
}

.watchlist-btn{
    position: relative;
    width: 100%;
    text-transform: capitalize;
    background: none;
    border: none;
    font-weight: 500;
    text-align: right;
    color: rgba(255, 255, 255, 0.5);
    margin: 5px 0;
    cursor: pointer;
    padding: 10px 5px;
    border-radius: 5px;
}

.watchlist-btn::before{
    content: '';
    position: absolute;
    top: 0;
    left: -5px;
    height: 35px;
    width: 35px;
    background-image: url(images/add.png);
    background-size: cover;
    transform: scale(0.4);
}

.watchlist-btn:hover{
    color: #fff;
    background: rgba(255, 255, 255, 0.1);
}

.pre-btn,
.nxt-btn{
    position: absolute;
    top: 0;
    width: 5%;
    height: 100%;
    z-index: 2;
    border: none;
    cursor: pointer;
    outline: none;
}

.pre-btn{
    left: 0;
    background: linear-gradient(to right, #0c111b 0%, #0c111b00);
}

.nxt-btn{
    right: 0;
    background: linear-gradient(to left, #0c111b 0%, #0c111b00);
}

.pre-btn img,
.nxt-btn img{
    width: 15px;
    height: 20px;
    opacity: 0;
}

.pre-btn:hover img,
.nxt-btn:hover img{
    opacity: 1;
}
Enter fullscreen mode Exit fullscreen mode
Output

Capture4

We are almost done. The last thing we have to do is make this card slider working. For that open app.js again.

// card sliders

let cardContainers = [...document.querySelectorAll('.card-container')];
let preBtns = [...document.querySelectorAll('.pre-btn')];
let nxtBtns = [...document.querySelectorAll('.nxt-btn')];

cardContainers.forEach((item, i) => {
    let containerDimensions = item.getBoundingClientRect();
    let containerWidth = containerDimensions.width;

    nxtBtns[i].addEventListener('click', () => {
        item.scrollLeft += containerWidth - 200;
    })

    preBtns[i].addEventListener('click', () => {
        item.scrollLeft -= containerWidth + 200;
    })
})
Enter fullscreen mode Exit fullscreen mode

And we are done.

So, that's it. I hope you understood each and everything. If you have doubt or I missed something let me know in the comments.

Articles you may find Useful

  1. Infinte CSS loader
  2. Best CSS Effect
  3. Wave Button Hover Effect
  4. Youtube API - Youtube Clone
  5. TMDB - Netflix Clone

I really appreciate if you can subscribe my youtube channel. I create awesome web contents.

Thanks For reading.

Discussion (12)

Collapse
sharpninja profile image
The Sharp Ninja • Edited

How is it "pure" if it has JavaScript?


EDIT: I've read the full article and am impressed. This really shows you don';t need or want to use some giant framework with HTML5.

Collapse
kunaal438 profile image
Modern Web Author

Who said JavaScript is not pure😅. If i used any library here then maybe its not pure but i don't think so that i am using any sort of library here

Collapse
sharpninja profile image
The Sharp Ninja

OK, if no libraries then I'll let it slide. :P

Collapse
marcodeev profile image
Marcos

Muy buen tutorial !!! gracias

Collapse
kunaal438 profile image
Modern Web Author

Thanks😄

Collapse
gdenn profile image
Dennis Groß

Good job.

Now I think about building my own Disney Plus clone for my portfolio. :D

Collapse
kunaal438 profile image
Modern Web Author

That sounds great 👍

Collapse
awaisrehman profile image
Awais_Rehman

That's awesome

Collapse
kunaal438 profile image
Modern Web Author

Thanks

Collapse
madhubankhatri profile image
Madhuban Khatri

Check out my projects.
I hope you like this

Collapse
madhubankhatri profile image
Madhuban Khatri

Wow! Good Content

Collapse
z2lai profile image
z2lai

Nice primer on working with DOM using vanilla JS. I might have missed it, but what CSS methodology are you using/recommend?