How to Build a Stacked Component Layout in React

The Stack layout pattern is one of the most simple and common layout patterns on the web. In this lesson, you will learn how to build the Stack primitive and how to make it configurable for your situation

Project Source Code

Get the project source code below, and follow along with the lesson material.

Download Project Source Code

To set up the project on your local machine, please follow the directions provided in the README.md file. If you run into any issues with running the project source code, then feel free to reach out to the author in the course's Discord channel.

Table of Contents

This lesson preview is part of the Composing Layouts in React course and can be unlocked immediately with a \newline Pro subscription or a single-time purchase. Already have access to this course? Log in here.

This video is available to students only
Unlock This Course

Get unlimited access to Composing Layouts in React, plus 70+ \newline books, guides and courses with the \newline Pro subscription.

Thumbnail for the \newline course Composing Layouts in React
  • [00:00 - 00:08] What's up guys, Travis here with another lesson in composing layouts in React. In this lesson we are going to learn about the stack.

    [00:09 - 00:25] One of the simplest and yet most common layout patterns found on the web is putting one element on top of another element with consistent space. From form labels to paragraphs of text to social media feeds, they all need to stack one thing on top of another with uniform space between them.

    [00:26 - 00:35] This problem is precisely what the stack primitive solves. In this lesson we are going to build the following widget.

    [00:36 - 00:42] It's a subscribe to our newsletter widget. As you will notice, we have a few parts to this widget.

    [00:43 - 00:53] There's a title section and a form section made up of two input groups and a button. The one thing that they all have in common is that they follow the same pattern .

    [00:54 - 01:03] They all stack vertically with space between them. Here's the same mock up with different space sizes pointed out.

    [01:04 - 01:20] So what we need is a way to enforce that all the items will stack in the block direction no matter if they are block or inline elements by default. We also need a way to provide consistent space between the elements without creating space around the stacked elements themselves.

    [01:21 - 01:32] That way the stack can remain composable in any other environment. So going forward in the rest of the lessons of this course, we are going to be using code sandbox.io.

    [01:33 - 01:44] If you want to follow along, I will provide a link to a starter project that you can fork. If you want to see the final code, there will be a link at the bottom of each and every lesson.

    [01:45 - 01:54] Now let's start off with some basic markup. You can create a new file called stack.jsx or you can call whatever you like.

    [01:55 - 02:14] If you want to change that, just come and change it on line seven. Now in these lessons, I'm choosing to structure my files in a way that should make it easier to focus on what's being taught and not necessarily the way I would structure a production React app.

    [02:15 - 02:32] Although React doesn't have an opinion on how to structure your files, I typically like to co-locate my components together as much as possible and then separate the files when components are reused across other parts of the application. So I've got this copied already.

    [02:33 - 03:01] So let's go ahead and just bring this in here. And of course, when I copy, I got to remember to import React.

    [03:02 - 03:21] And there we go. Now the first problem we need to solve is to get the label to stack on top of our input.

    [03:22 - 03:29] This problem is easily solved with the single line of CSS. So we're going to start by creating our actual stack component.

    [03:30 - 03:39] To do this, we're going to import styled from styled components. And this is already pre-installed as you'll see.

    [03:40 - 03:53] It's already installed over here. But if you haven't, it's just as simple as searching for styled components and you can like click it on the left-hand side.

    [03:54 - 04:04] So let's make our first styled component called stack, which is equal to styled .div. And we're doing two back ticks.

    [04:05 - 04:17] And then we're going to write our CSS in here. Display grid.

    [04:18 - 04:37] Now when we set display grid, we haven't at this point set any row or columns. So we have implicitly created a single column and it will implicitly create a new row for each element that is added inside of our stack.

    [04:38 - 04:42] Now we can use our stack. We can update it like this.

    [04:43 - 05:04] Let's just start off with these input groups. And as you can see over here, we've already got our label and our input to stack on top of each other.

    [05:05 - 05:13] Now the first thing you'll notice is that not only are the labels stacked on top of each other, they are. Now we're going to take up the entire width of the column.

    [05:14 - 05:28] If you want to override this behavior, you'll simply need to use justify items property on the stack one to change all of them or use the justify self property on the individual items you want to change. In this case, we don't need to do that.

    [05:29 - 05:34] Everything's working just fine. So all we need to do now is set space between them.

    [05:35 - 05:58] We can set space between them using the gap property. Now the value that we add into the gap property can be any values CSS size unit such as a pixel, a percentage or rem.

    [05:59 - 06:10] But we don't want to just hard code it into 10 pixels for example. What we want to do is have this configurable via props.

    [06:11 - 06:25] So what we're going to use is style component string interpolation property. And I've already got this copied and it looks like this.

    [06:26 - 06:40] And we're going to worry about the way this styling changes while we do that. Now what we're doing here, let's take a step back.

    [06:41 - 06:51] We already know about JavaScript string template property, which is within two back takes. You can create a string.

    [06:52 - 07:11] For example, let's go const age equals 50. And we go let age string equal.

    [07:12 - 07:25] Let's put it to back takes. And we're going to say you are and we're going to want to do some type of decision here.

    [07:26 - 07:40] We want to say you are old if you're over 45 and young if you are 45 or less. So here we can go age is greater than 45.

    [07:41 - 07:51] If that's the case, we're going to say you are old. Otherwise, we're going to say you're young.

    [07:52 - 08:07] And then here we're going to console log age string. Now code sandbox IO, if you've never used it before, let's refresh that so we can clear some of those errors.

    [08:08 - 08:16] You can see it says you are old down here. And if we go ahead and change this to 30.

    [08:17 - 08:45] Now says you are. Now this is the default way that a regular template literal works is that everything inside of this dollar sign curly and then a final curly, it breaks out of the string mode and evaluates it and then we go back into string mode for the rest.

    [08:46 - 09:00] Now there are things called tag template literals. And that's exactly what this is a tag template literal, which is a way to custom parse that JavaScript expression.

    [09:01 - 09:21] So we can actually have more control over what's going on inside of the dollar sign curly instead of just evaluate whatever gets handed to us. So when we are using style dot div and we break into this curly, we actually have the option to pass in a function.

    [09:22 - 09:36] And that function, oops, that function has access to the props that we pass into the this component. And we can return a string that will ultimately be used in our CSS.

    [09:37 - 09:58] So in this specific example, we are taking the props and we are going to, if we have provided a props dot gutter, we will evaluate that and return whatever string is passed into the gutter prop. But if we don't pass in a string to the gutter prop, we're going to default to one ramp.

    [09:59 - 10:15] That way there's always some gap in between our items. So once again, now we can actually do a little bit more.

    [10:16 - 10:22] Let's take for example, these inputs. We don't want them to just have the default one ramp.

    [10:23 - 10:46] As you can see, it's already been given over there. We want to give them, let's give them a gutter equal to 0.25 ramp or one quarter ramp.

    [10:47 - 11:00] This little bit closer, it's a little bit more realistic to what an input group would have. Now, we also need in between here and here we need to have a gutter.

    [11:01 - 11:13] So let's put on, let's call put stack there. And you can see now this is a stack.

    [11:14 - 11:25] This group is stacked on top of this group, which is stacked on top of this button. And each one has a one ramp gutter placed in between them.

    [11:26 - 11:40] Let's do the same thing with the heading level two in our paragraph. And let's don't just go with the default gutter.

    [11:41 - 11:57] Let's give it a gutter equal to 0.5 ramp. And we're doing awesome here.

    [11:58 - 12:04] Now we just need to get a bigger gutter here. Now something probably bigger than the default.

    [12:05 - 12:15] So let's put a stack around the entire thing. And that's pretty good, but we want a little bit bigger here.

    [12:16 - 12:22] So in this case, let's go twice as big. Let's go to ramp.

    [12:23 - 12:39] There we go, that looks a lot better. So now we have a component that will universally stack all of its children and will separate them via a configurable value that's passed into the gutter prop.

    [12:40 - 12:43] We could stop here. This does exactly what we want.

    [12:44 - 12:53] But I'm going to recommend one more tweak, I should say, sorry, to this gutter prop. Right now we are allowing any value to be passed into this gutter.

    [12:54 - 13:07] But for consistency, it's best practice to adopt some type of spacing scheme when you're laying out items on the web. Choosing a good spacing scheme is beyond the scope of this course.

    [13:08 - 13:19] And I'm not a designer. So I'm not going to go into all the different methodologies to create a spacing scheme.

    [13:20 - 13:33] Also if you work with a design team, they probably already have a spacing scheme set up in their style guide that they're using. Let's just create a spacing scheme.

    [13:34 - 13:44] In bedrock layout primitives, there is a spacing scheme that's based on t-shirt sizes. And it looks something like this.

    [13:45 - 13:52] I just copied it. So we're creating an object here called spacing map.

    [13:53 - 14:03] We have some different sizes. The large, for example, is one RAM, medium is half a RAM, and so on and so forth.

    [14:04 - 14:31] So instead of just accepting any value that gets passed in here, let's adjust it like this. So spacing map, and we're going to pass in the props.getter.

    [14:32 - 15:03] And then we're going to default to the large. Now, by the way, I gloss over this earlier if you're not aware of what these double hooks or double question marks mean, this is called a null knowledge coalescing operator.

    [15:04 - 15:15] If this evaluates to anything that's nullish, meaning null or undefined, then it will be null. It will go to this value as a backup.

    [15:16 - 15:26] But if this does evaluate to something, then this is ignored. So what happens is we can pass in a prop to our getter.

    [15:27 - 15:41] And if that getter problem, if that key is not inside of the spacing map, then it will just default back to one RAM getter. You can see, based off the way, since we haven't changed anything yet, that's what's happened.

    [15:42 - 16:06] Everything is now one RAM over here. So let's update our component and just with the power of copy and paste, because I've already have it available, we can get the same exact thing to work exactly how we did before.

    [16:07 - 16:29] But instead of passing in the values directly, now we're passing in properties like extra large, medium, small. And this gives a little bit more description to what these spacing values are in relation to each other.

    [16:30 - 16:33] And that's it. We're done.

    [16:34 - 16:43] At the end of the lesson, there is a link to the sandbox with all the code. And that's it.

    [16:44 - 17:05] So now that we have our stack items, we need to now fall kind of, we need to fix the most common problem besides stacking, which is putting one thing next to the other. So in the next lesson, we're going to learn about the split layout primitive.

    [17:06 - 17:06] We'll see you on the next lesson.