Build Youtube in React 16: Video Infobox
Well, well well, glad you still stick around.
There are two omore bigger components left in our
Here’s what we’re up to. Click on the image to see it in high resolution.
In this tutorial we will work on the
Youtube info box, i.e. the component directly underneath the video’s view count.
Let’s take a closer look. Click on the images to see them in high resolution.
If we click the
Show More button, the component is supposed to show the entire description that is available. Per default, it only shows two lines.
2 Building the Youtube VideoInfoBox component
2.1 Creating the files
VideoInfoBox component will only be responsible for laying out some data. It will not reach out to an
API or access our
Redux store later on. Therefore, we consider it a presentational component and put it into
- Create a new directory inside
src/componentsand call it
- Create a
VideoInfoBox.scssfile inside the directory you just created
2.2. Designing Youtube’s video info box
Let me give you another image to show you how we’ll create the markup for our info box.
Our component clearly has a two dimensional layout. Therefore we’ll use
CSS-Grid again. We could also built it using
flexbox, but then we would need nested
Grid makes our life way easier. So let’s get started.
2.3 Youtube Video info box CSS Grid layout
Here’s the basic layout structure of our
Our root element is a
div with the class
.video-info-box. We make it a
grid container by setting
display: grid. As already shown in the image above, we need a
2x3 grid, i.e. a grid with two rows and three columns. We don’t really care about the rows’ height, that’s why we specify
auto two times in our grid property.
In the original Youtube app, the channel’s image is
48px x 48px. Since the circular channel image will go into the top left cell, we give the column a width of
58px to have
10px of additional whitespace. The third column is different though as it will hold our
Subscribe button. We set the column’s width to
max-content so that the text in the subscribe button never wraps.
Now that we have the first and the third column out of the way, we just set the width of the second column to
Grid will take care of the rest.
In addition, we want our channel image, the video’s title and the subscribe button to be on one imaginary horizontal line because that looks better. Therefore, we instruct
Grid to center its children vertically by setting
2.4 Updating our Watch component
To see the result of our efforts in action, we actually need to use our newly created component somewhere. Head over to our
Watch component and update the markup of the
render function like so:.
Note that we removed the
2.5. Refining video info box
We have our
Grid, but we still need to put some content there.
Let me show you the content of the
render function first:
The markup itself should be relatively straight forward. Before I show you the
SCSS, please have a look at the image below where I marked the horizontal grid lines in red and the vertical ones in black.
I’ve also annotated their grid line numbers, so the following
SCSS is easier to understand.
.channel-image class puts the channel’s image into the top left cell. We place the video’s title and its publication date into the second column of the first row by applying the
.video-info class. Our subscribe button is put into the top right cell by applying the
In the original Youtube app, the video’s description text block has a maximum width of
615px. That’s why we apply a
max-width constraint in our
.video-description class. This
SCSS class that is applied to the element that holds the video’s description text.
Here’s what we have so far: Click on the image to see it in high resolution.
Great, we’re done with the basic layout. As we already discussed earlier, we want the video’s description to be sort of collapsed. The user should only see the first two lines of it. If the user clicks expand, we show the entire content. So let’s get to it.
2.6 Adding expanding capability to video info box
Now, we’re going to do something we have not done before. We will add local state to a component. We will introduce a
collapsed to our local state so that our
VideoInfoBox knows whether it’s currently showing the full text or not. Note that it is our component’s business whether it is currently collapsed or not. Therefore this property will not belong to our global state.
In our constructor, we set our component’s initial state and add a
collapsed property whose default value is
true. This flag is supposed to indicate whether we currently only show two lines of the video’s description or the entire text.
We also added the
onToggleCollapseButtonClick event handler. This function is just flipping our local state’s
setState function will force the component to re-render.
2.7. Video Info Box dynamic styling
To make the video
info box' styling dynamic we need to apply different
CSS depending on whether it is currently collapsed or not. So please go ahead and add the following code to your
We apply a little bit of cosmetics to the
p element and explicitly set its
line-height. By setting the
max-height to twice a paragraph’s
line-height, we automatically put a height constraint on the element if the
.collapsed class is applied. The
overflow-y: hidden property makes sure that overflowing content is not displayed.
To show the entire text, we just need to apply the
.expanded class which removes the
max-height constraint and allows the container to vertically expand as much as it needs to display the full content.
Oh yeah, one more thing. We explicitly set the
0px because the
Semantic UI SCSS applies a default bottom margin of
1em which we don’t want in this case.
2.8. Toggling the video info box description
Let’s make use of our new
SCSS classes in our component. First, the component needs to determine what
SCSS class it should apply. Therefore, it needs to check the collapsed boolean of its local state and pick the desired
Please put the following code at the top of the
So depending on whether our
collapsed flag is set, we adapt our
SCSS classes accordingly and also change our button’s title.
As a last step, we need to adapt our component’s markup.
Note that we added a new
div inside the
.video-description element that applies the
descriptionTextClass. We put all our text (i.e. all paragraphs) in here.
In addition, the component now reacts to the click event of the Show more / Show less button and displays the value of the
buttonTitle variable as text.
Here’s how the collapsed version of our info box looks like.
Click on the image to see it in high resolution.
And here is the expanded version:
That was more logic than expected. Let’s add tests have this component done as well.
- Create a new directory inside
src/components/VideoInfoBoxand call it
- Add a
VideoInfoBox.unit.test.jsfile inside of the directory you just created.
In order to capture the component’s markup in both
collapsed state we added two tests. Since
VideoInfoBox is collapsed per default, we can just
render it without any props or something to get the markup when it’s collapsed.
setState in our component to trigger a re-render when the button is clicked. To get the component’s markup in
expanded state, we could programatically trigger the
However, we might refactor this component in the future and might not rely on a button anymore. Therefore, let’s set the state directly from within our test by calling
If we change the component’s state later on, this test will fail. But that’s ok. We want it to fail, so we know something has changed.
You can run your tests by executing
4 Wrap Up
Aaaand we’re done with yet another component.
Note that we did not add the logic for displaying links properly. We will do that once we fetch video descriptions from the
Youtube endpoint. For now, the
VideoInfoBox component is good enough.
Watch component still needs an element that displays the video’s comments. We’ll do that in the next tutorial.
As always, thanks for reading.
You can find the entire code on our Github repository.Follow @productioncoder
Please 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.