Zoom Clone with React and 100ms SDK (part I)
Tags: react, webdev, javascript, beginners
Published: 2022-07-04 10:09:48

Video conferencing tools, like Zoom, and GoogleMeet allow individuals to meet and work together productively "face-to-face" when meeting in person isn't possible. This makes meeting remotely much more human, which is essential in order to help users feel and stay connected.

Zoom is a cloud-based video conferencing platform that can be used for video conferencing meetings, audio conferencing, webinars, meeting recordings, and live chat. You need a free account to start your own calls for up to 100 people; paid versions can support up to 1,000 people. You can make unlimited phone calls, hold unlimited meetings, and even record both.

## Prerequisites and What You Will Learn

As a prerequisite to understanding and following this tutorial, you should have basic knowledge of React and CSS.

In this article, you will learn how to build this clone using the following concepts:

- Creating a **new React Application**
- **Styling with CSS**.
- Setting up the Video Conference (This section is covered in detail here).

This tutorial will cover the following:

- Creating a Zoom Clone layout.
- Setting buttons for muting and unmuting the audio and video for both local and remote peers.
- Setting buttons for sharing the screen for presentation for the host.
- Setting buttons for recording the meeting
- Creating a chat layout

## Let’s Build Our Zoom Clone App

### Developers Setup

For this tutorial, you will install packages with NPM, so you need to have [Node installed](https://nodejs.org/en/) on your system. Alternatively, you can use [yarn](https://yarnpkg.com/) if you prefer that.

For this tutorial, I used [Node v16.15.0.](https://nodejs.org/dist/latest-v16.x/docs/api/) I encourage you to use the same version if you are coding along.

- **Create a React App**: Use npm for boilerplate to **create react** app.

```jsx
npx create-react-app zoomclone
```

The first thing to do now is to navigate into your public folder and open the index.html file, we need to import bootstrap in the index.html file for styling.

```html

    <!-- Optional theme -->
		//This should be pasted in the <head> tag

    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap-theme.min.css"
        integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp" crossorigin="anonymous">

    <script defer src="https://unpkg.com/peerjs@1.3.1/dist/peerjs.min.js"></script>
    
		<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
    
		<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>

    <link rel="stylesheet" href="style.css">
    <script src="https://kit.fontawesome.com/c939d0e917.js"></script>
   
   //While the bootstrap.min.js should be pasted in the <body> tag
  <body>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/js/bootstrap.min.js"
    integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa"
    crossorigin="anonymous"></script>
  </body>
```

The next thing to do is to navigate inside your **SRC** folder and create a folder naming it **Components.**

Inside the Component folder, let’s create a navBar.jsx file. It should look like this:

```jsx
import React from 'react';
import './navBar.css';

const NavBar = () => {
    return(
        <nav className="navbar">
            <div className="container-fluid">
                <div className="navbar-header">
                    <button type="button" className="navbar-toggle collapsed" data-toggle="collapse"
                        data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
                        <span className="sr-only">Toggle navigation</span>
                        <span className="icon-bar"></span>
                        <span className="icon-bar"></span>
                        <span className="icon-bar"></span>
                    </button>
                    <a className="navbar-brand" href="https://google.com">
                        <img className="navbar-logo"
                            src="https://static.zoom.us/static/6.1.6656/image/new/ZoomLogo.png"
                            srcSet="https://static.zoom.us/static/6.1.6656/image/new/ZoomLogo.png 1x"
                            alt="Zoom logo" aria-hidden="true" data-iml="1243.5999999940395"
                            data-atf="true" />
                    </a>
                </div>
            <div className="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
                <ul className="nav navbar-nav navbar-right">
                    <li>
                        <a href="https://zoom.com" style={{fontSize: 15}}> Join</a>
                    </li>
                    <li>
                        <a href="https://zoom.com" style={{fontSize: 15}}>Host</a>
                    </li>
                    <li>
                        <a href="https://zoom.com" style={{fontSize: 15}}>Sign In</a>
                    </li>
                    <li>
                        <a className='signup'>SIGN UP IT'S FREE</a>
                    </li>
                </ul>
            </div>
        </div>
    </nav>
    )
}

export default NavBar;
```

Next, is to create a navBar.css file so we can style the Navbar.

```css
.navbar {
    background-color: #fff;
}
.navbar-logo {
    width:50%;
    height:100%;
    margin-left: 30px;
}
#time_date {
    font-size: 17px;
    font-weight: 800;
    text-decoration: none;
    color: #000;
}
.signup {
    background-color: #F26D20;
    margin-top: 5px;
    border-radius: 30px;
    color: #fff;
}
```

Inside the Component folder, let's create our landing page. This is what we see first when we open the application. This for us will be the foundation of our application.

Inside the Component folder, create a file and name it JoinForm.jsx. 
Your JoinForm.jsx file should be like this:


```jsx
import React from 'react';
import './style.css';
import NavBar from './navBar';

const JoinRoom = () => {
    return(
        <>
            <NavBar />
            <hr></hr>
            <div id="content_container" style={{minHeight: 872}}  className="zoom-newcontent ">
                <div id="content" className="main-content">
                    <div className="mini-layout" id="join-conf">
                        <div className="mini-layout-body">
                            <h1 style={{fontSize: 25}}>Join Meeting</h1>
                            <div className="box">
                                <form id="join-form" className="form-vertical">
                                    <div className="form-group confno" style={{marginBottom: 30}}>
                                        <div className="controls">
                                            <label htmlFor="join-confno" style={{color: 747486, fontSize: 15,marginBottom: 10}}>Meeting ID or Personal Link Name</label>
                                            <input aria-describedby="rule-tip" id="join-confno" 
                                                type="text" 
                                                className="form-control input-lg confno" 
                                                autoComplete="off" maxLength="100" 
                                                placeholder="Enter Meeting ID or Personal Link Name"
                                                name="userName"
                                                required
                                                />
                                            <div id="errorContainer" className="wc-new-syle">
                                                <div id="join-errormsg" className="error hideme"><i></i><span></span></div>
                                            </div>
                                        </div>
                                    </div>
                                    <div className="form-group" style={{marginBottom: 16}}>
                                        <div className="controls">
                                            By clicking "Join", you agree to our <a href="https://zoom.us/terms">Terms of Services</a> and <a href="https://zoom.us/privacy">Privacy Statement</a>
                                        </div>
                                    </div>
                                    <div className="form-group" style={{marginBottom: 72}}>
                                        <div className="controls wc-new-syle">
                                            <button id="btnSubmit" role="button" style={{ width: 200, padding: 5}} className="btn btn-primary user submit">Join</button>
                                        </div>
                                    </div>
                                    <div className="form-group">
                                        <div className="controls wc-new-syle">
                                            <a id="btnRoomSystemJoin" className="doc" href="https://zoom.us/meeting/rooms">Join a meeting from an H.323/SIP room system</a>
                                        </div>
                                    </div>
                                </form>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </>       
    )
}
export default JoinRoom;
```

Let’s style the JoinForm, create a file, and name it styles.css

```css
#content_container {
    min-height: 600px;
}
.form-control.input-lg.confno {
    font-size: 20px;
    height: 56px;
    text-align: center;
    width: 100%;
    margin-left: 0;
}
h1{
    text-align: center;
    margin-top: 100px;
}
#join-form {
    max-width: 360px;
    margin: 0 auto;
    margin-top: 50px;
}
#join-form .form-control, #join-form .btn {
    border-radius: 12px;
}
.links {
    font-size: 16px;
    color: #68687b;
}
.links a {
    color: #0E71EB;
    display: inline-block;
}
@media (max-width: 767px) {
    .form-horizontal .form-group {
        margin-left: 0;
        margin-right: 0;
    }
    #roomSystemDialog .modal-footer {
        padding-left: 20px;
        }
}
.form-control.input-lg.confno {
    font-size: 15px;
    text-align: left;
}
.form-control:focus {
    border: 2px solid #0E72ED;
}
.input-lg{
    height: 40px !important;
}
#join-conf .btn.user {
    height: 40px !important;
    font-size:16px;
    line-height:31px !important
}
.wc-new-syle{
    text-align: center;
}
```

The JoinForm page should look like this: 


![JoinForm](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f6w1f5u6z7blypu8mnvu.png)

The upper part is the navBar we imported in the JoinForm.js file.

Now, let’s create a ControlBar, this is where we set the control buttons for our zoom application, this is an integral part of the application we are building.

```jsx
import React from "react";

const ControlBar = () => 
  return (
    <div class="main__controls">
        <div className="main__controls__block">
            <div className="main__controls__button main__mute_button">
               <i className="fas fa-microphone"></i>
               <span>Mute</span>
            </div>
            <div className="main__controls__button main__video_button" >
               <i className="fas fa-video"></i>
               <span>Stop Video</span>
            </div>
            <div className="main__controls__button">
                <i className="fas fa-shield-alt"></i>
                <span>Security</span>
            </div>
            <div className="main__controls__button">
                <i className="fas fa-user-friends"></i>
                <span>Participants</span>
            </div>
            <div className="main__controls__button">
                <i className="fas fa-comment-alt"></i>
                <span>Chat</span>
            </div>
            <div className="main__controls__button main__video_button" >
                <i className="fas fa-desktop"></i>
                <span>Share Screen</span>
            </div>
            <div className="main__controls__button">
                <i className="fas fa-record-vinyl"></i>
                <span>Record </span>
            </div>
            <div className="main__controls__button">
                <i className="fas fa-laugh"></i>
                <span>Reactions</span>
            </div>
            <div className="main__controls__button">
                <i className="fas fa-retweet"></i>
                <span>Apps</span>
            </div>
            <div className="main__controls__button">
                <i className="fas fa-clipboard"></i>
                <span>Whiteboard</span>
            </div>
        </div>
        <div className="main__controls__block">
          <div className="main__controls__button">
            <span className="leave_meeting">Leave Meeting</span>
          </div>
        </div>
    </div>
  );
};

export default ControlBar;
```

💥The control buttons are ready but not functional yet, in the next series to this article, you would see how the buttons work.

Now, let’s create our room, this is where the video tile displays.

Create a file and name it Room.js, the room.js file should look like this:

```jsx
import React from "react";
import ControlBar from "./Control/ControlBar";

import './view.css';

const Room = () => {

  return (
    <div class="main"> 
      <div class="main__left">
        <div class="main__videos">
          <div id="video-grid">
            <div className="flex flex-col mt-20">
              <div className="flex bg-gray-900 w-screen min-h-screen p-2 flex-wrap">
                <h3>VIDEO</h3>
              </div>
            </div> 
          </div>
        </div>
        <ControlBar />
      </div>
      <div className="main__right">
          <div className="main__header">
              <h6>Chat</h6>
          </div>
          <div className="main__chat_window">
              <ul className="messages">
              
              </ul>
          </div>
          <div className="main__message_container">
              <input id="chat_message" type="text" placeholder="Type message here..." />
          </div>
      </div>
    </div>
  );
};

export default Room;
```

The room should look like this with the control bar below it.

![RoomJs Image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2mq5p6sfb386zn7qswf5.png)

Finally! that's the end of this section, I hope you really found it interesting and easy to follow through.

In the next article, we will be making use of 100ms SDK for video conferencing and also assign functions to our controlBar.

[100ms](https://www.100ms.live/) is a cloud-based platform that lets you integrate video and audio conferencing into your application. It provides [APIs and SDKs](https://www.100ms.live/docs/javascript/v2/foundation/basics) through which you can set up and manage telecommunication services on the client and server-side applications.

## Conclusion

In this tutorial, you have successfully created a zoom clone layout and styled its buttons. What the Zoom App lacks now are the functionalities of each buttons (audio, participants, share screen), the video displayed, reactions (emojis and stickers), chat, and how to copy, share links and add another user to the video conference. I'll walk you through implementing this in Part 2.

This piece is a first step towards the main goal of us building a zoom app clone with react js and 100ms.  Click on the [link](https://dev.to/benjaminbusari/zoom-clone-app-with-react-and-100ms-sdk-part-ii-57lc) to continue the tutorial.

You might also be interested in other guides using React and 100ms SDK:

[Building a Google Classroom Clone with React and 100ms SDK](https://www.100ms.live/blog/google-classroom-clone-react-100ms#why-100ms%3F)

[Building a Twitch Clone with React](https://www.100ms.live/blog/twitch-clone-in-react)

[Building a Discord Stage Channel](https://www.100ms.live/blog/build-discord-stage-channel-clone-hms?utm_source=cta&utm_medium=inline&utm_campaign=twtcl&utm_id=blogCTA)