Build Youtube in React 07: Home Feed and Video Preview
1 Youtube Home Feed Mockups
We’re finally about to develop one of Youtube’s main components: its home feed. Let’s look at our mock to see what we’re up to.
Click the image to get it in high resolution.

Video thumbnails are free stock images from https://www.pexels.com/ that explicitly don’t require any attribution
We can see that we need some grid like component that shows us videos for different categories.
2 Adding VideoPreview component
2.1 Mockups
Let’s start with the component that holds the video thumbnail, its description and metadata. We will call this component VideoPreview
. Here’s how it looks when we zoom in a little bit.
Click the image to get it in high resolution.
2.2 Adding VideoPreview and Home component skeletons
The first question – as always – is: is this a stateful or a presentational component? It makes sense to assume that probably some parent component will fetch data from an endpoint and then create a VideoPreview
component for each fetched video. Therefore, we can presume that our VideoPreview
component will get its information via props
. We will therefore put it into the src/components
directory.
- Create a new directory inside
src/components
and name itVideoPreview
- Inside this directory, create a
VideoPreview.js
and aVideoPreview.scss
file
The typical workflow in a React
project is to break the app down into smaller components and then start building them bottom up. However, since we want to actually see the results of our efforts as we are gradually adding more components, we will create the Home
feed component skeleton now. The Home
component will certainly fetch some information from the Youtube API and is therefore a stateful component.
- Create a new directory inside
src/containers
and name itHome
- Inside this directory, create a
Home.js
and aHome.scss
file
We also make use of our Home
component in src/App.js
for better testing
2.3 Adjusting Youtube Home feed styling
But wait, what is that? Apart from the side bar and the top bar, we don’t see anything. How did that happen? Remember how we implemented SideBar?
We added a display: fixed
CSS property somewhere. If you add an element like this, you basically glue it to a specific position of the view port and you remove it from the normal document flow. Therefore, we need to give the Home
component a left margin that is equal to its side bar’s width.
Also remember that the top bar is fixed as well. Therefore, we also need a to give our Home component a margin-top
property. Fortunately we have already put these widths in our styles/shared.scss
file. So let’s just make use of it.
2.4 Displaying the thumbnail image in VideoPreview
Let’s build out the VideoPreview
component step by step and take care of the video thumbnail image first.
Here is our markup:
Now you might have asked yourself why the markup is nested the way it is. Well, that’s because of our SCSS
.
We will use CSS-Grid
to accomplish the layout we want. If you are not familiar with CSS Grid
, I highly recommend reading this excellent article. CSS-Grid
is currently the most powerful lay-outing system that CSS
offers. It is more powerful than Flexbox
because it allows us to create two-dimensional layouts. Flexbox
only allows us to create one dimensional layouts unless we nest several flex containers in one another.
2.5 Lay-outing VideoPreview with CSS-Grid
Let’s revisit our VideoPreview
mockup again and let’s specifically think about how we would lay it out in a grid.
We would probably go with a grid that has one column and two rows. The first grid cell (here in green) will display the video image thumbnail. The second grid cell displays some meta information like the video’s title, the amount of views etc.
Now you might be wondering why the grid lines are marked in different colours. The horizontal grid lines are all marked in red and get assigned a number starting form 1
. The same is true for the vertical lines which are marked in black. However, since we only have one column, we only have two vertical lines instead of three. Why is this that useful? Well, because that’s how CSS-Grid
(or Grid in short) works.
Let me show you the code that will create the layout we want.
If we want to use CSS-Grid
we have to make one element a so called grid-container. Similar to Flexbox
where we make an element a flex-container
by adding display: flex
, we’re now adding display:grid
to make the element a grid container. The actual magic lies in the grid: 118px auto / 210px
statement.
This means that our grid will have two rows and that the first row will have a height of 118px
. That means that the first and the second red line will be 118px
away from each other. Why? Well because that’s the height of a video thumbnail in Youtube. At least that’s what I saw in the Chrome Dev tools. The second keyword is auto
. This basically means: size the second row automatically and make sure that the content fits in somehow. Note that this is a rather vague and intuitive explanation of what auto
does. But I won’t cover the CSS-Grid
specification here in detail.
The text after the /
describes the columns we want to have. As shown in our little image above, we will only have one column. This column will have a width of 210px
because that’s how Youtube sizes its video thumbnails. Feel free to open up your developer console in Youtube and to check it out for yourself.
The .image-container div
contains the video preview image. By setting grid-row to 1 / 2
, we instruct CSS Grid
to place it between the first second horizontal grid line
, i.e. between the first two red horizontal lines. By setting grid-column
to 1 / 2
, we also force to put our div
into the first column. Well that’s kind of clear, we only have one column after all.
2.6 Displaying video duration by using absolute positioning
I haven’t shown you the SCSS
for displaying the video duration yet. That is, because we are using absolute positioning
and because that would have distracted you from understanding how we use CSS-Grid
.
Now you also come to understand why we use position:relative
inside our .image-container
class. We need it for the positioning of our video duration label.
So here’s our SCSS
magic.
Let’s think again how we want our video duration label to be positioned. It should always stay at the bottom right corner. This is a perfect use case for absolute positioning
. By using absolute positioning
, we tell our .time-label div
to be 0px
away from both the bottom and the right. Absolute positioning
basically allows us to glue an element somewhere relative
to a parent element. But there is one more thing. When we use absolute
positioning, the browser positions our element relative to the first positioned
ancestor? What? Well that means our element gets positioned to the first ancestor which has either display: absolute
or display: relative
in its CSS
. Since we always want to position our div
relative to the .image-container
, we’ve given it the position: relative
property. Without this, our SCSS
does not work.
Apart from that we do a little bit of cosmetics in our .time-label
class, we add a little bit of margin and make the background dark and a little bit opaque. I guess this does not need much explanation.
If you are confused with how the file now actually looks, you can scroll down and look at all the code. You can also head over to our Github repository and have a look at the file directly. Note that there might be more CSS
than we have here because we will add additional functionality to this component later on.
2.7 VideoPreview channel title, views and video title
Right now, we only have a placeholder image and a hard-coded video duration. But we still need to display the video’s title, its release date and the channel name.
We create a new element with the class .video-info
and place it directly below where our .image-container
element ends. There are a few things are worth mentioning here in terms of CSS
.
We only want our title to span two lines at maximum. Therefore, we added the .show-max-two-lines
class. By making the overflowing content “invisible” and by setting the maximum height to two times the element’s line-height
, we make sure, that we hide part of the title if it is too long.
In case of the channel’s name, things are a little bit different. Since we want the channel’s title to be on exactly one line, we add white-space: now-wrap
. In case the channel’s title is too long, we abbreviate it with ...
This is what text-overflow: ellipsis
does.
2.8 Full VideoPreview code
Here’s the complete code for our component:
4 Tests
To wrap up, let’s just add a snapshot test. Since our component currently doesn’t accept any props
, one snapshot test is sufficient.
- Create a
__tests__
directory inside yourVideoPreview
component - Create a
VideoPreview.unit.test.js
file inside the directory you have just created.
5 Wrap up
That was a lot of code for one seemingly easy component. But it works. Let’s have a look at the result in our browser.
Now you might have asked yourself why we wrote it in CSS-Grid
. Well, first of all it’s a good exercise and second, we will make this component more flexible in the future by adding more lay-outing options to it. I think CSS-Grid
makes this a little bit easier, but we could have also achieved the same thing in Flexbox
.
Click on the image to see it in high resolution.
As always, you can find this project’s code in our Github repo.
Follow @productioncoderPlease follow me on Twitter @productioncoder to stay up-to-date. I’m happy to receive feedback of any kind.
If you are interested in more high-quality production-ready content, please enter your email below.
Recent Comments