Unsplash API - How to make unsplash clone | Javascript tutorial
Tags: javascript, css, html, beginners
Published: 2021-12-09 15:10:45

Hello guys, In today's article you'll learn to create this unsplash clone. If you don't know what unsplash is, unsplash is a website/company which offers royalty free images for personal or business use. We'll today create this website using unsplash API. It's a great javascript project for beginner. 

So, without wasting more time, let's start. To see project demo or you want a video tutorial. You can watch the tutorial below.

#Video Tutorial

{% youtube LoWBkkmgRBE %}

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

[ Source Code ](https://www.patreon.com/posts/59711793)

#Code

So, let's start with our folder structure. You can see the files we'll use, below.

![Unsplash API - Javascript Project](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/awrwyjd80ykjm730u2aw.png)
 
So, let's make our home page first. 

#Home Page
###Header Section

In our home page, we have a beautiful header section. To create that. Open `index.html` file. Inside that, code these elements.

```HTML
<header class="header-section">
        <div class="header-content">
            <h1 class="logo">logo</h1>
            <p class="sub-line">the best royalty free images you can find here.</p>

            <form action="search.html">
                <input type="text" autocomplete="off" name="search" class="search-box" placeholder="search image">
                <button class="search-btn" type="submit">search</button>
            </form>
        </div>
</header>
```
Without CSS HTML is nothing, is't it. So, let's style our header element.

```CSS
*{
    margin: 0;
    padding: 0;
    box-sizing: border-box;
    font-family: 'roboto', sans-serif;
}

.header-section{
    width: 100%;
    height: 100vh;
    position: relative;
    background-image: url('../img/bg.png');
    background-size: cover;
    display: flex;
    justify-content: center;
    align-items: center;
    text-align: center;
}

.logo{
    font-size: 80px;
    font-weight: 400;
    color: #fff;
    text-transform: capitalize;
}

.sub-line{
    color: #fff;
    padding: 20px 0 30px;
    font-size: 20px;
    text-transform: capitalize;
    word-spacing: 2px;
    position: relative;
    font-weight: 300;
}

.sub-line::after{
    content: '';
    position: absolute;
    bottom: 0;
    left: 50%;
    transform: translateX(-50%);
    width: 60%;
    height: 1px;
    background: #fff;
}

.sub-line::before{
    content: '';
    position: absolute;
    bottom: -5px;
    left: 50%;
    transform: translateX(-50%);
    width: 10px;
    height: 10px;
    background: #fff;
    border-radius: 50%;
}

.search-box{
    display: block;
    margin: 60px auto 20px;
    width: 100%;
    height: 40px;
    border-radius: 5px;
    padding: 10px;
    border: none;
    outline: none;
    text-transform: capitalize;
}

.search-btn{
    padding: 10px 30px;
    border-radius: 5px;
    text-transform: capitalize;
    border: none;
    outline: none;
    cursor: pointer;
    background: #0a1113;
    color: #fff;
}
```
Those are lots of styling. After giving these CSS, we are done with our header section.

######Output

![Unsplash clone - Javascript Tutorial](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w8a55y1pdceq434jjslf.png)
 
Isn't it looking great.

###Gallery Section
After header section, we have image recommendations or image gallery in our home page in mansory layout. To create mansory layout, first we need some elements or images.

After header section in `index.html`
```HTML
<section class="gallery">
    <img src="img/img (1).png" class="gallery-img" alt="">
    <img src="img/img (1).png" class="gallery-img" alt="">
    <img src="img/img (1).png" class="gallery-img" alt="">
    <img src="img/img (1).png" class="gallery-img" alt="">
    <img src="img/img (1).png" class="gallery-img" alt="">
    <img src="img/img (1).png" class="gallery-img" alt="">
    <img src="img/img (1).png" class="gallery-img" alt="">
    <img src="img/img (1).png" class="gallery-img" alt="">
</section>
```
For now create 8 image elements. And give them some styles.

```CSS
/* gallery */

.gallery{
    width: 100%;
    padding: 40px;
    background: #fff;
    columns: 4;
    column-gap: 20px;
}

.gallery-img{
    width: 100%;
    height: 100%;
    object-fit: cover;
    margin-bottom: 20px;
    border-radius: 5px;
    cursor: pointer;
    background: #f9f9f9;
}
```
######Output
![Unsplash Clone](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8z2defcy6qrd3wzqmlhp.png)

If you create less than 8 images, you'll probably don't see images in 4 columns. This is because, we have used `columns` CSS property to create grid. Note - we are not using grid here, cause grid create a fixed size row and columns and we want images to have their proportions. `Columns` property is used to define columns for elements in CSS without using grid. This don't restrict you with fixed row height.

So, now you can remove the hard coded image elements from `index.html`. and let's make it with JS. So open `app.js`.

In `app.js` file, first you need to store your unsplash API key. If you don't know how to create one, then [check this](https://youtu.be/LoWBkkmgRBE?t=865).

```JS
const access_key = 'your api key';
```
Once you got your key, we need random photo url, so that we can get random photos, you can find the url in the unsplash documentation. but for your ease, here it is.

```JS
const random_photo_url = `https://api.unsplash.com/photos/random?client_id=${access_key}&count=30`;
```
Here `access_key` is your api key. And **I am using JS template literals here.**

Now, make a function `getImages`. This function will make request to random photo URL.

```JS
let allImages; // this will store all the images

const getImages = () => {
    fetch(random_photo_url)
    .then(res => res.json())
    .then(data => {
        allImages = data;
        makeImages(allImages);
    });
}
```
`allImages` will store the fetched data, so we can access the data after receiving it outside the function. So, now once we got the images, we need to make dynamic image elements, for that make `makeImages` function.

```JS
const gallery = document.querySelector('.gallery');

const makeImages = (data) => {
    data.forEach((item, index) => {

        let img = document.createElement('img');
        img.src = item.urls.regular;
        img.className = 'gallery-img';

        gallery.appendChild(img);

    })
}
```
So, after this you should see random images being fetched from API and created with JS dynamically. 

```JS
getImages()
```
>Make sure to call the function

######Output
![Unsplash Clone](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fioxqghllxk6faj2pin0.png)
 
Great! now, let's create image popup effect. For that again open your `index.html` file.

###Image popup

Create image popup before `gallery`. Or you can it after also it doesn't really matters 😂

```HTML
<!-- popup window -->
<div class="image-popup">
    <button class="close-btn"></button>
    <a href="#" class="download-btn">download image</a>
    <img src="img/img (1).png" class="large-img" alt="">
    <button class="controls pre-btn"><img src="img/pre.png" alt=""></button>
    <button class="controls nxt-btn"><img src="img/nxt.png" alt=""></button>
</div>
```
```CSS
/* image popup */

.image-popup{
    position: fixed;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 80%;
    height: 80vh;
    background: #f9f9f9;
    box-shadow: 0px 5px 50px rgba(0, 0, 0, 0.25);
    border-radius: 10px;
    transition: .5s;
    display: flex;
    justify-content: center;
    align-items: center;
}

.image-popup.hide{
    display: none;
    opacity: 0;
}

.close-btn{
    position: absolute;
    top: 10px;
    left: 10px;
    width: 20px;
    height: 20px;
    background: #ff4f4f;
    border-radius: 50%;
    border: none;
    cursor: pointer;
}

.download-btn{
    text-transform: capitalize;
    padding: 10px 20px;
    background: #192f2e;
    color: #fff;
    text-decoration: none;
    border-radius: 5px;
    position: absolute;
    right: 10px;
    top: 10px;
}

.large-img{
    height: 80%;
    width: auto;
    max-width: 80%;
    object-fit: cover;
    border-radius: 10px;
}

.controls{
    background: none;
    border: none;
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    cursor: pointer;
}

.pre-btn{
    left: 20px;
}

.nxt-btn{
    right: 20px;
}
```
######Output
![Unsplash Clone](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vz4coin9taks21dlntn4.png)

You can see in above styles, we have `hide` class which is setting `display` to `none`. So add `hide` class to `image-popup` element. You can also remove the image source from `large-img`

Now, let's make it functional with Javascript.

```JS
let currentImage = 0; // will track the current large image

const makeImages = (data) => {
    data.forEach((item, index) => {

        ..previous code..

        // popup image

        img.addEventListener('click', () => {
            currentImage = index;
            showPopup(item);
        })

    })
}
```
This above code will add click event to all the images, so that we can open the popup. So, now let's create `showPopup` function.

```JS
const showPopup = (item) => {
    let popup = document.querySelector('.image-popup');
    const downloadBtn = document.querySelector('.download-btn');
    const closeBtn = document.querySelector('.close-btn');
    const image = document.querySelector('.large-img');

    popup.classList.remove('hide');
    downloadBtn.href = item.links.html;
    image.src = item.urls.regular;

    closeBtn.addEventListener('click', () => {
        popup.classList.add('hide');
    })

}
```
In this function, first we are selecting all the HTML elements using `querySelector` method. And then removing `hide` class from popup element. also setting up download image btn link along with image source. And yes, we are also add close functionality.

So, we just have to make controls now.

```JS
// controls

const preBtns = document.querySelector('.pre-btn');
const nxtBtns = document.querySelector('.nxt-btn');

preBtns.addEventListener('click', () => {
    if(currentImage > 0){
        currentImage--;
        showPopup(allImages[currentImage]);
    }
})

nxtBtns.addEventListener('click', () => {
    if(currentImage < allImages.length - 1){
        currentImage++;
        showPopup(allImages[currentImage]);
    }
})
```
Above code is also very simple. In above code, we are selecting the previous and next buttons and adding click event to them. Inside the events, I am checking for condition to validate end image. 

So great. We are done with our home page. Let's create our search page now.

#Search Page
Our search page is very simple. To start, copy all the elements from `index.html` except header section. and paste it inside this file. After done with that, make a search box at the very start of body tag.

```HTML
<form action="search.html" class="search-container">
    <input type="text" autocomplete="off" name="search" class="search-input" placeholder="search image">
    <button class="search" type="submit">search</button>
</form>
```
Make sure you link `search.css` & `app.js` file to it. Now, add these form styles to `search.css`. 
```CSS
.search-container{
    width: 100%;
    height: 60px;
    background: #0a1113;
    padding: 10px 40px;
    display: flex;
    justify-content: space-between;
}

.search-input{
    width: 95%;
    height: 40px;
    border-radius: 5px;
    border: none;
    outline: none;
    padding: 20px;
    text-transform: capitalize;
}

.search{
    background: none;
    border: none;
    color: #fff;
    text-transform: capitalize;
    cursor: pointer;
}
```
After all of this, you should see something like this.

######Output
![Unsplash Clone](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mcx6ugrz762vvqbb45jp.png)

Now, let's fetch images related to search keyword. Inside `app.js`

```JS
let searchParam = location.search.split('=').pop(); // this will give extract the search keyword from URL

const search_photo_url = `https://api.unsplash.com/search/photos?client_id=${access_key}&query=${searchParam}&per_page=50`; // this is search image URL
```

Now, create a function to make request to the URL.
```JS
const searchImages = () => {
    fetch(search_photo_url)
    .then(res => res.json())
    .then(data => {
        allImages = data.results;
        makeImages(allImages);
    });
}
```
After this, we just need to check we are on home page or search page and call the function according to it. So instead of calling simple `getImages();` wrap that to this condition along with this code.

```JS
if(searchParam == ''){
    getImages();
} else{
    searchImages();
}
```
So above condition is simple when we open home page, our `searchParam` will be an empty string. That's why I am comparing that to check for the page.

######Output

![Unsplash Clone](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zd1gdjt338ci7btxwaps.png)

>I searched for cars

So, that's it. Great work guys. We are done with the project. So, how is this project, and did you learn something new from this.

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. [Best CSS Effect](https://dev.to/kunaal438/css-the-best-css-effects-of-all-time-most-underrated-web-ux-2chj)
2. [Infinte CSS loader](https://dev.to/kunaal438/quick-css-make-infinity-loading-animation-for-your-next-website-187k)
3. [Disney+ Clone](https://dev.to/kunaal438/how-to-create-disney-plus-clone-for-beginner-in-2021-html-css-js-m3p)
4. [Youtube API - Youtube Clone](https://dev.to/kunaal438/create-working-youtube-clone-with-search-box-youtube-api-2a6e)
5. [TMDB - Netflix Clone](https://dev.to/kunaal438/how-to-create-netflix-clone-netflix-clone-with-hmtl-css-js-989)

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

<a href="https://www.youtube.com/c/modern_web?sub_confirmation=1"><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jeitpawvax07cx7r9yoa.png"></a>

[Source Code](https://www.patreon.com/posts/59711793)
Thanks for reading