Twitch Frontend with ReactJS?!

David Rakosi
Clever Programmer
Published in
9 min readJan 18, 2021

Getting your first job as a developer is super hard.

Most entry level jobs require at least 1 year experience… (What??! Shouldn’t entry jobs require nothing but a good mindset and will to learn?) Anyways, you want to get that job, you need to show stuff.

Okay let’s switch to the interviewer’s point: you probably know nothing about coding (Massive respect for all the interviewers who learn a little coding just so they can choose better developers. Massive massive respect.), you received 300 applications to a Junior Web Developer position and so on… which portfolio is more appealing in that 30 seconds you’re looking at it? The one that has super unique, you haven’t even seen type of web-app that’s flashy and all but you don’t have too much time clicking it through, or the one that has Twitch, the most popular streaming platform, the platform where his/her kid is on 5 hours a day watching random guys playing with video games?

Yea, Twitch. A recruiter has no time to click through your stuff, they open it and this happens: ‘oh, hey, it’s Twitch! This guy knows his sh*t! Yo, Laura, let’s fit this guy in next Tuesday! Seems like a good match for the Junior Web whatever!’

Alright, hope you’re convinced. Let’s get started!

Step 1: Setup, dependencies

Let’s start the app by running

$ npx create-react-app twitch-clone

Wait…

$ cd twitch-clone
$ npm start

Wait ‘till Safari opens with your app. Looks nice, huh? That’s the React logo. Okay, let’s delete app.test.js, logo.svg. Also delete the 2nd row in App.js, and everything in the <header> tag. Also, import the Fontawesome CDN. You can do that by going to fonteawesome.com, registering an account and following the onscreen steps.

App.js should look somewhat like this:

import './App.css';function App() {  return (
<div className="App">
</div>
);
}
export default App;

Step 2: Header

Try to mimic the thing. Go, open up twitch.tv, try to make something that looks like it.

Guide:

  • Create 3 divs
  • First div: add all the stuff on the top left corner (logo, Following, Browse, Esports, Music, Icon)
  • Second div: input field, icon — wrap the icon into a separate div so we can give the whole thing a nice look
  • Third div: icons, div, icon — notice that the ‘Get Bits’ button is not a regular button. You need to wrap that to a div so we can style that nicely. Finally, add an avatar (you can use just your profile picture for that.)
  • Give it a nice look! Be brave to use the flexbox and experiment. Have a discipline to actually recreate the Twitch look! I know you can do it! (Colors to use: header background: #18181b, textbox background: #4a4a4c, search icon background: #2b2b2d)

In case you need help, here’s the full code for both the JSX and the CSS file, but remember: ⚠️ the harder you try and the more time you put in the better results you’ll get ⚠️

import React from 'react'
import './Header.css'
const Header = () => {
return (
<div className='header' >
<div className="header__left">
<img className='header__leftLogo' src="twitch.jpg"/>
<h2>Following</h2>
<h2>Browse</h2>
<div className="vl"></div>
<h2>Esports</h2>
<h2>Music</h2>
<i className="fas fa-ellipsis-h"></i>
</div>

<div className="header__center">
<input type="text" placeholder='Search' />
<div className="header__centerLogoContainer">
<i className="fas fa-search"></i>
</div>
</div>
<div className="header__right"> <div className="header__rightContainer">
<i className="fas fa-crown"></i>
<i className="fas fa-inbox"></i>
<i className="fas fa-comment-alt"></i>

<div className="header__rightBits">
<i className="fas fa-gem"></i>
<h4>Get Bits</h4>
</div>
<img src='profilepic.jpg'/>
</div>
</div>
</div>
)
}
export default Header.header {
height: 5rem;
border-bottom: 1px solid black;
display: flex;
align-items: center;
background-color: #18181b;
z-index: 100;
position: sticky;
top: 0;
}
.header__left {
display: flex;
align-items: center;
flex: 1;
}
.header__leftLogo {
object-fit: contain;
height: 3rem;
margin-left: 20px;
}
.header__left>h2 {
margin: 15px;
}
.vl{
border-left: 1px solid #4a4a4c;
height: 3rem;
}
.header__left>i {
margin-left: 15px;
}
.header__center {
background-color: #4a4a4c;
height: 3.5rem;
display: flex;
width: 25%;
border-radius: 8px;
overflow: hidden;
align-items: center;
}
.header__center>input {
outline: none;
background-color: transparent;
flex: 1;
margin-left: 15px;
font-size: large;
border: none;
}
.header__centerLogoContainer {
background-color: #2b2b2d;
width: 50px;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
}
.header__right {
display: flex;
flex: 1;
justify-content: flex-end;
}
.header__rightContainer {
display: flex;
justify-content: space-between;
align-items: center;
}
.header__rightContainer>i {
margin: 20px;
}
.header__rightContainer>div {
margin: 20px;
}
.header__rightBits{
display: flex;
align-items: center;
background-color: #4a4a4c;
height: 3.5rem;
padding-left: 20px;
padding-right: 20px;
border-radius: 15px;
}
.header__rightBits>i{
margin-right: 5px;
}

Alright, let’s import it to App.js and let’s keep going! 🔥

Step 3: Sidebar

Again, take a close look at the actual Twitch. Notice the main parts: Followed Channels, Recommended Channels, actual channel names, all the details next to it. Also let’s not forget about the part down there!

Guide:

  • We need 2 divs — top and bottom
  • Top div: Add section titles and the channel list as external components. Don’t forget the props!
  • Write the Channel component and style it. Play with divs and flexbox.
  • Bottom div: add an icon and the input field
  • Try to replicate the actual look of Twitch! If you used the css file from above, try to use that as a resource. Don’t look down until you’re sure you can’t move forward.

Sidebar.js 👇

import React from 'react'
import Channel from './Channel'
import './Sidebar.css'
const Sidebar = () => {
return (
<div className='sidebar' >
<div className="sidebar__top">

<h5>FOLLOWED CHANNELS</h5>
<Channel avatar='avatar.jpg' name='cleverprogrammer' followers='816k' />
<h5>RECOMMENDED CHANNELS</h5> <Channel avatar='avatar.jpg' name='cleverprogrammer' followers='816k' /> <p className='sidebar__topShowMore' >Show More</p> </div> <div className="sidebar__bottom">
<div className="sidebar__bottomContainer">
<i className="fas fa-search"></i>
<input type="text" placeholder='Search to Add Friends' />
</div>
</div>
</div>
)
}
export default Sidebar

Sidebar.css 👇

.sidebar {
padding: 10px;
width: 13%;
background-color: #1f1f23;
display: flex;
flex-direction: column;
}
.sidebar__top {
flex: 1;
}
.sidebar__top>h5 {
margin-top: 25px;
margin-bottom: 25px;
}
.sidebar__topShowMore{
color: #a970ff;
cursor: pointer;
}
.sidebar__bottom {
position: fixed;
bottom: 0;
height: 4rem;
display: flex;
align-items: center;
justify-content: center;
border-top: 1px solid #4f4f52;
}
.sidebar__bottomContainer {
background-color: #4f4f52;
width: 90%;
display: flex;
height: 2.5rem;
border-radius: 8px;
align-items: center;
padding-left: 10px;
padding-right: 5px;
}
.sidebar__bottom>div>input {
background-color: transparent;
border: none;
outline: none;
font-size: large;
width: 100%;
margin-left: 10px;
}

Channel.js 👇

import React from 'react'
import './Channel.css'
const Channel = ({ avatar, name, followers }) => {
return (
<div className='channel'>
<div className="channel__details">
<img src={avatar} alt="avatar" />
<p>{name}</p>
</div>
<p>🔴 {followers}</p>
</div>
)
}
export default Channel

Channel.css 👇

.channel {
cursor: pointer;
width: 100%;
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 15px;
margin-bottom: 15px;
}
.channel:hover {
background-color: #25252c;
}
.channel__details {
display: flex;
align-items: center;
}
.channel>div>img {
object-fit: contain;
margin-right: 5px;
width: 40px;
border-radius: 50%;
}

Step 4: The Body part

This components just wraps 2 other and a div which is responsible for the margin on the right hand side.

Div 1 — Stream: this piece requires a TON of divs and CSS. I honestly wouldn’t try to write everything down. This is a part where you need to figure out and put in some time to understand how things are connected to each other. There’s the cheatsheet below.

One thing though, you need to remember, embed your live stream. Open up YouTube Studio, create a new stream, secondary click on the video, hit copy embed code, paste it. That’s it! Yes! Really!

Div 2 — Profile: This part is a complete mix whatever we have already done! A full recap of all the things you’ve already figured out! Try to use all the things and you’ll be able to build it!

The whole body has this background saying ‘cleverprogrammer’ several times, that’s actually an SVG code I grabbed from Twitch itself. Go ahead and use that!

Alright, down below are the snippets, but try to figure these out! Don’t forget the icons, flexbox, embedding other YouTube videos to the below portion.

Body.js

import React from 'react'
import './Body.css'
import Profile from './Profile'
import Stream from './Stream'
const Body = () => { return (
<div className="body">
<div className="body__left">
<Stream />
<Profile />
</div>
<div className="body_rightPlaceHolder"></div>
</div>
)
}
export default Body

Body.css

.body {
background-color: rgb(255, 153, 0);
background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' version='1.1' height='200px'><text x='15' y='27%' fill='white' font-size='4rem' font-weight='600' opacity='0.1' font-family='Roobert,Helvetica Neue,Helvetica,Arial,sans-serif'>cleverprogrammer cleverprogrammer cleverprogrammer cleverprogrammer cleverprogrammer cleverprogrammer cleverprogrammer cleverprogrammer </text><text x='5' y='60%' fill='white' font-size='4rem' font-weight='600' opacity='0.1' font-family='Roobert,Helvetica Neue,Helvetica,Arial,sans-serif'>rammer cleverprogrammer cleverprogrammer cleverprogrammer cleverprogrammer cleverprogrammer cleverprogrammer cleverprogrammer cleverprog</text><text x='0' y='93%' fill='white' font-size='4rem' font-weight='600' opacity='0.1' font-family='Roobert,Helvetica Neue,Helvetica,Arial,sans-serif'>rprogrammer cleverprogrammer cleverprogrammer cleverprogrammer cleverprogrammer cleverprogrammer cleverprogrammer cleverprogrammer cleve</text></svg>");
flex: 1;
display: flex;
height: 100vh;
overflow: scroll;
}
.body__left {
width: 96%;
}

Stream.js

import React, { useEffect, useState } from 'react'
import './Stream.css'
import axios from './axios'
import { SettingsBackupRestoreTwoTone } from '@material-ui/icons'
import VideoEmbed from './VideoEmbed'
const Stream = () => {
return (
<div className='stream' >
<div className="stream__container">
<div className="stream__status">
<div className="stream__statusContainer">
<div className="stream__statusContainerTop">
<div className="stream__statusIndicator">OFFLINE</div>
<h2>Check out the below streams from Clever Programmer</h2>
</div>
<div className="stream__statusInfo">
<i className="fas fa-bell"></i>
<p>You will be notified when cleverprogrammer is live</p>
</div>
</div>
</div>
<div className="stream__videoEmbed">
<iframe
width="500"
height="295"
src="YOUR-YT-EMBED-LINK"
frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
allowfullscreen></iframe>
</div>
</div>
</div>
)}
export default Stream

Stream.css

.stream {
height: 50%;
display: grid;
place-items: center;
}
.stream__container {
display: flex;
}
.stream__status {
width: 400px;
height: 295px;
background-color: #1f1f23;
margin-right: 30px;
}
.stream__statusContainer {
margin: 25px;
display: flex;
flex-direction: column;
height: 245px;
}
.stream__statusIndicator {
background-color: white;
color: #1f1f23;
border-radius: 8px;
width: fit-content;
padding: 5px 10px;
}
.stream__statusContainerTop {
flex: 1;
}
.stream__statusInfo {
display: flex;
align-items: center;
}
.stream__statusInfo>i {
margin-right: 20px;
}
.stream__status>div>div>h2 {
font-size: 35px;
}
.stream__video {
height: 295px;
width: 500px;
}
.stream__videoEmbed {
height: 295;
width: 500;
}

Profile.js

import React from 'react'
import './Profile.css'
import { LiteYouTubeEmbed } from "react-lite-youtube-embed";
import RecentItem from './RecentItem';
const Profile = () => { return (
<div className='profile' >
<div className="profile__top">
<div className="profile__topLeft">
<img src="logo.jpg" />
<div className="profile__topLeftDetails">
<h1>cleverprogrammer</h1>
<h3>820k followers</h3>
</div>
</div>
<div className="profile__topRight">
<i className="fas fa-heart graybg"></i>
<i className="fas fa-bell graybg"></i>
<i className="fas fa-ellipsis-v"></i>
</div>
</div>
<div className="profile__menu">
<h2 className='active' >Home</h2>
<h2>About</h2>
<h2>Schedule</h2>
<h2>Videos</h2>
<h2><i class="fas fa-arrow-up"></i></h2>
<h2>Chat</h2>
</div>
<div className="profile__recent">
<h2>Recent broadcasts</h2>
<div className="profile__recentItems">
<RecentItem url={'LINK-TO-VIDEO'} title={'YOUR VIDEO TITLE'}/>
<RecentItem url={'LINK-TO-VIDEO'} title={'YOUR VIDEO TITLE'}/>
<RecentItem url={'LINK-TO-VIDEO'} title={'YOUR VIDEO TITLE'}/>
<RecentItem url={'LINK-TO-VIDEO'} title={'YOUR VIDEO TITLE'}/>
</div>
<div className="profile__categories">
<h2>cleverprogrammer's recently streamed Categories</h2>
<img src="category.jpg" />
<h3>Science & Technology</h3>
</div>
</div>
</div>
)}
export default Profile

Profile.css

.profile {
background-color: #0e0e10;
}
.profile__top {
display: flex;
align-items: center;
}
.profile__topLeft {
display: flex;
align-items: center;
flex: 1;
}
.profile__topLeft>img {
object-fit: contain;
height: 100px;
margin: 40px;
border: 2px solid #35353a;
border-radius: 50%;
padding: 3px;
}
.profile__topRight {
font-size: 30px;
}
.profile__topRight>I {
margin: 10px;
padding: 10px;
border-radius: 8px;
width: 40px;
text-align: center;
}
.profile__topRight>.graybg {
background-color: #35353a;
}
.profile__menu {
display: flex;
margin-left: 40px;
margin-top: 30px;
margin-bottom: 55px;
}
.profile__menu>h2 {
margin-right: 15px;
cursor: pointer;
}
.profile__menu>h2>i {
transform: rotate(45deg);
margin-right: -5px;
}
.profile__menu>.active {
color: #a970ff;
border-bottom: 5px solid #a970ff;
padding-bottom: 10px;
}
.profile__recent {
margin-left: 40px;
}
.profile__recentItems {
display: flex;
}
.profile__categories {
margin-top: 40px;
}
.profile__categories>h2 {
margin-bottom: 20px;
}
.profile__categories>h3 {
margin-top: 10px;
}

RecentItem.js

import React from 'react'
import './RecentItem.css'
const RecentItem = ({ url, title }) => {
return (
<div className='item' >
<iframe
width="400"
height="235"
src={url}
frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
allowFullScreen={true}></iframe>
<div className="item__details">
<img src="https://static-cdn.jtvnw.net/ttv-boxart/Science%20&%20Technology-285x380.jpg" />
<div className="item__detailsText">
<h4>{title}</h4>
<p>cleverprogrammer</p>
<p>Science & Technology</p>
</div>
</div>
</div>
)}
export default RecentItem

RecentItem.css

.item {
display: flex;
flex-direction: column;
width: 400px;
overflow: hidden;
white-space: nowrap;
margin-right: 20px;
}
.item__details {
display: flex;
margin-top: 25px;
}
.item__details>img{
object-fit: contain;
height: 60px;
margin-right: 10px;
}

And that’s it! You’ve built a Twitch looking React app!

Hope you got value out of it! In case you have any questions, don’t hesitate reach out to me!

In case you got pumped, enroll to our course Profit with JavaScript so you’ll always be up to date with the latest and greatest technologies in the web development world! Enroll here: https://www.cleverprogrammer.com/pwj

All the best to everyone out there and happy coding! ✌️

Ya man,
DR. MERN

--

--