How to Display Specific Components in Each Tab in React
All right, so we got the call back in there. Now what we want to do is actually change the components status the object status so we can render the actual component that belongs to this tab.
Guide Tasks
  • Read Tutorial
  • Watch Guide Video
Video locked
This video is viewable to users with a Bottega Bootcamp license

So what we should do is go into our callback where we're just console logging the title and let's actually go through our state and change the value of the one that we clicked. We're also going to have to change this one back to false if we click on our requests.

So what we need to do is map over it and do that. So let's say const tabs = this.state.tabs; and then let's just map over those by saying tabs.map and then let's say tab and index and put an arrow function and then what we can do is just say if tab.title is equal to title then tab.active is true.

dashboard.js

handleTabChange = (title) => {
    const tabs = this.state.tabs;

    tabs.map((tab, index) => {
        if(tab.title == title) {
            tab.active = true
        }
    })
}

So basically we're just mapping over this and saying hey if this is equal to the one we just clicked then change active to true and you'll say okay but if we click on requests. It's going to change that to true but this is going to also still be true, so it's going to render both components.

Now that's true but it's actually not going to do anything at this point because if we go in and we click there(Newsletter or Requests) it's not going to do anything. And the reason being is because we're not actually changing our state we're just copying it and we're changing tabs we're not changing the tabs that belongs to state.

And it's not re rendering and passing these taps in, so what we have to do say this.setState tabs and that should fix it. Now this is going to make it so this displays as well except for this component will also be displaying because it's also set to true and we're not really setting it back to false.

So let's go check it out. Let's login and you'll see it says newsletter click on requests and it's now displaying both of those.

large

Now they're both set to true so it's displaying both of them. Now what we have to do is basically set back all the other tabs back to false not just newsletter because we could theoretically just say if tab.title is newsletter then set it to false. But we don't want to do that because what happens when we have more tabs right? It's not going to work.

So what we want to do right here is say tab.active is false. So it's going to go through all of them and set them all to false even ones that are false. But then it's going to say hey if the tab is equal to the title let's actually set it to true.

So we can actually do is say else and then put tab.active is equal to false. So it's going to say hey if it's not this title we want it to be inactive we don't want to display it. Cool let's get rid of index and we don't need these parentheses anymore because we only have one parameter.

dashboard.js

handleTabChange = (title) => {
    const tabs = this.state.tabs;

    tabs.map(tab => {
        if(tab.title == title) {
            tab.active = true
        } else {
            tab.active = false
        }
    })
}

Let's go to the browser and login and you'll see that it works now.

large

Sweet, that's exactly what we want, it's functional and it looks good. Now let's go ahead and actually get the styles in there on these titles. Because right now it's not really showing which one is selected.

So what we can do is we can either put some styles in our dashboard.js and manually apply them or we can go into tabnav.js and we can say hey in props.tabs.map where we're putting them out. Let's give it a class name and if the tab is active let's apply another class.

So over here in className what we can do is let's just take out this class name and let's put a variable here and let's just say className. And let's say const class name is equal to and then in back ticks, and the reason we're using back ticks is because we're going to put a conditional in here and have it display a selected style if the active is true.

So let's say tab.active ? if it's active then we want to say tab-nav__active else just return nothing we don't want any extra styles.

tabnav.js

this.props.tabs.map((tab, index) => {
    const className = `tab-nav__tab ${tab.active ? 'tab-nav__active' : ''}`
    return <a key={index} onClick={() => this.props.handleClick(tab.title)} className={className}>{tab.title}</a>
})

So let's just go check that this is still working, it's not going to display the styles because we haven't written any, and let's just make sure that there's no bugs. It looks good to me, and its still working. OK so let's go write some styles to display the active status.

And it's really simple it's just a red color and a boarder bottom. So let's go into tab-nav.scss and let's say and active since we called it tab-nav__active and let's just say color is color red BA and border bottom is two pixels solid color red BA.

tab-nav.scss

&__active {
    color: $color-red-BA;
    border-bottom: 2px solid $color-red-BA;
}

Let's check it out and awesome that looks great.

large

although it looks like it's too high. So we want to do is put that padding back in there. So let's go ahead and do this, let's see our grid real quick. Let's go into Firefox and let's click on the grid for that let's go to scss here and select in the layout tab-nav__tabs. So what I want to do is basically just tell the item here the newsletter and requests.

We want to say that each one of these tabs is the height of the tabs. Because right now it's not and it's causing problems and that wouldn't matter like we can just put in padding, except that's going to generate another problem and it's kind of like a wing it kind of a guess as to how much we need to put to get this line down here.

And that's not accurate it's not really clean. So let's just make the tab the same high as its parent container. So let's go into our code and let's say tab and since we are on a grid on tabs what we can do is just say that this is the start of the rows on tabs and this is the end of the rows.

tab-nav.scss

&__tabs {

    grid-template-rows: [s] 1fr [e];
}

So we can just say on each one of these tabs we want a grid row of start to end.

tab-nav.scss

&__tab {
    grid-rows: s/e;
}

So basically what it's going to do is it's going to say hey put this tab on the grid of the tabs and it will extend across the entire height or the entire row. So let's check it out back in Firefox again. And you'll see now that it's not entirely the height so all we have to do is just say height is 100 percent go back into Firefox and you'll see the height now.

large

So that looks good except for now what you'll see is that newsletter is way too high up. So all we have to do is say padding top is 50 percent on each one of these items here. So let me deselect this grid and you'll see the line is right on it which looks fantastic but now the text is way too high.

So let's see, so what we can do is say template rows and then we can say, this might not work but let's try it, you could say 1fr and 1fr then we can say middle then what we can do is just have start in the middle and then I'll go to the end so the border will still be on the bottom but the text will start in the middle.

tab-nav.scss

&__tabs {
    grid-row: tabs-s/tabs-e;

    display: grid;
    grid-template-rows: [s] 1fr [m] 1fr 1fr [e];
    grid-template-columns: repeat(auto-fill, 1fr);
    grid-auto-flow: column;
    justify-items: center;
    align-items: center;

    justify-content: center;

    grid-column-gap: 4.6rem;
    border-bottom: 1px solid $color-gray-E6;
}   

&__tab {
    grid-row: m/e;

    height: 100%;
    font-size: 1.6rem;
    font-weight: 500;
    line-height: 2rem;
    text-align: center;
    width: 9rem;
    // padding-bottom: 2rem;
    // border-bottom: 1px solid $color-red-BA;
    border-bottom: 2px solid transparent;
}

Okay cool that looks pretty good.

large

Now the reason it's so low is because it's starting in the middle exactly what we told it to do, but the problem with that is that the top of the text is starting in the middle. So let's see it's not selecting the grid. Okay so let's open Firefox and you'll see it's starting exactly where we told it to start.

So what we can do is we can just say hey we want another row and we want it to start around there. So let's go back to our code and let's just put another 1fr after the middle and that should fix it.

tab-nav.scss

grid-template-rows: [s] 1fr [m] 1fr 1fr [e];

It'll put it about 1/3 down the content but then the border is going to touch the bottom so let's try that out in Firefox here.

large

You'll see that looks great, it's right in the middle and we got the border at the bottom. Okay let's deselect that it looks exactly like what we want and it selects it. Now you'll see that kind of moves it up which we don't really want. So what we can do and the reason that's happening is because we have a border bottom of two pixels.

So what we can do is we can either set a border bottom by default on the tab and set it to transparent (border-bottom: 2px solid transparten;), and that will fix it because it's already there and the two pixels can't push it up because the two pixels are already there it's just invisible.

So that works or if you want to know another approach what you can do is get rid of that line. You'll get that problem again and what we can do is we can just say padding-bottom: 2px; and then in the &__active we can say padding-bottom: 0px;.

So basically what's going to happen is it's going to say hey there's 2 pixel padding bottom but then when we apply a border let's get rid of that padding bottom and it will have the same height. So let's going into Chrome and try it out and you'll see it looks good.

So that's kind of a more messy approach though, so let's go and let's delete both of these paddings and let's just give it a border-bottom: 2px solid transparent;. So those are the two approaches and this is the cleaner approach so that's the one we'll use. But I just wanted to let you know that there are multiple ways of getting things done in scss, too many in my opinion but yeah both of those work.

Okay so that looks good, let's go ahead and in the next video let's handle the newsletter component so let's get started on this. So lets commit our code.

Terminal

git status
git add .
git commit -m "styled tab-nav and made it fully functional"

Resources

Source code