This video is available to students only

Inline Component

Clustering is one way to do responsive inline layouts, but sometimes we want to switch the direction that the items are flowing when we cross a certain threshold. In this lesson, we will learn how to build the Inline primitive that does just that.

The InlineCluster primitive solved a very common inline layout problem. However, there is another common problem which is similar but needs its own custom solution. In this lesson, we will learn how to make a variant of the InlineCluster, called Inline, which will let us stretch one or more items. It will also allow us to switch to a stack layout when the width decreases below a threshold.

The problem: the MenuBar v2#

In this lesson, we are going to build a second version of our MenuBar widget:

Menu Bar mockup wide

In this version of the MenuBar, we need to have everything stay inline and not cluster. In addition, we need the center section to stretch and fill the extra available space, but cluster in the center when there is no extra space available.

It will also need to switch from a horizontal, inline layout to a vertical, stack layout when the inline size is less than a 40rems, like this:

Menu Bar mockup narrow

The solution#

You can follow along by forking the starter project.

In our MenuBar, we need items in the middle section (the menu items) to cluster in the center. We already have a primitive that solves that problem: the InlineCluster primitive. Let's look at our initial markup, which is already using the InlineCluster primitive:

And this is how it looks:

Menu Bar step 0

In the above code, we have separated our menu into three parts, the logo, the menu items, and our sign-in/sign-up sections. Here is the same image, with the three sections colored to make it easier to see:

Menu Bar step 0 with color bars

The next thing we need to do is move these sections to be inline, but this time we don't want them to cluster like the InlineCluster. So let's start making our Inline primitive. The Inline primitive needs to do all the things that the InlineCluster can do, like setting the gutter, justify, and align props. The only thing we don't want it to do is cluster. Luckily, we don't have to recreate all those same properties again on our Inline primitive. We are going to take advantage of styled-components ability to extend the styles of other components:

In the above code, we pass the InlineCluster as an argument to styled. Doing that will mean that we have all the style logic of the InlineCluster, but now we can build on top of it. Unlike the menu items in the middle, we don't want our menu bar components to cluster. To prevent clustering we need to override the flex-wrap property set in the InlineCluster by setting it flex-wrap in the Inline primitive to nowrap.

One of the requirements we need to fulfill is to have the menu items in the center to grow to take up all available space. One of the properties you can set on a flex-item is the flex property. The flex property can be passed a number and it will stretch to fill as much space as possible. Only those flex-items that have the flex property set will grow and it will grow in relation to other flex-items value.

Based on the rules of Encapsulated CSS, we know we need to set values like flex that impact the layout of an element in the parent component. In the above code, we are using the direct child combinator to set the flex property to 1 on all the three direct children, the logo, the menu items, and the sign-in/sign-up section. By setting all the direct children to have a flex value of 1, they will all grow equally.

Now we can wrap our start using the Inline primitive, like this:

And now our menu looks like this:

Menu Bar step 1

And here is that same image with colors to make the sections easier to see:

Menu Bar step 1 with colored sections

Sometimes, we want all items to stretch uniformly this way, but for our menu bar we want only the second item to stretch. What we need is a way to set which item or items will stretch and grow. Let's add a prop called stretch that accepts either a number that represents the index of the child that we want to stretch, or the strings: all, start, or end. Let's do a little refactoring:

In the above code, we check to see if the stretch prop is a number. If it is, we will use the :nth-child pseudo selector. The :nth-child pseudo selector allows you to select an element that is the "nth child". We just need to pass into the selector which child it is that we want to have stretched. For example, if we wanted to select the third child, we would write our selector > :nth-child(3){}. In JavaScript, index numbers start at 0, but in CSS indexes start at 1. So we need to add one to our number to convert from a 0-based index to a 1-based index, which is why our code will return > :nth-child(${stretch + 1}) { flex: 1 }.


This page is a preview of Composing Layouts in React

Start a new discussion. All notification go to the author.